<commit_before>// Filename: texProjectorEffect.cxx
// Created by:  drose (25Jul04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "texProjectorEffect.h"
#include "cullTraverserData.h"
#include "texMatrixAttrib.h"
#include "lensNode.h"
#include "config_pgraph.h"
#include "nodePath.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "datagram.h"
#include "datagramIterator.h"

CPT(RenderEffect) TexProjectorEffect::_empty_effect;
TypeHandle TexProjectorEffect::_type_handle;

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
TexProjectorEffect::
~TexProjectorEffect() {
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::make
//       Access: Published, Static
//  Description: Constructs a TexProjectorEffect that modifies
//               no stages at all.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) TexProjectorEffect::
make() {
  // We make it a special case and store a pointer to the empty effect
  // forever once we find it the first time, as an optimization.
  if (_empty_effect == (RenderEffect *)NULL) {
    _empty_effect = return_new(new TexProjectorEffect);
  }

  return _empty_effect;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::add_stage
//       Access: Published, Static
//  Description: Returns a new TexProjectorEffect just like this one,
//               with the indicated projection for the given stage.
//               If this stage already exists, its projection
//               definition is replaced.
//
//               The relative transform between the "from" and the
//               "to" nodes is automatically applied to the texture
//               transform each frame.
//
//               Furthermore, if the "to" node is a LensNode, its
//               projection matrix is also applied to the texture
//               transform.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) TexProjectorEffect::
add_stage(TextureStage *stage, const NodePath &from, const NodePath &to) const {
  TexProjectorEffect *effect = new TexProjectorEffect(*this);
  StageDef &def = effect->_stages[stage];
  def.set_from(from);
  def.set_to(to);
  return return_new(effect);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::remove_stage
//       Access: Published, Static
//  Description: Returns a new TexProjectorEffect just like this one,
//               with the indicated stage removed.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) TexProjectorEffect::
remove_stage(TextureStage *stage) const {
  TexProjectorEffect *effect = new TexProjectorEffect(*this);
  effect->_stages.erase(stage);
  return return_new(effect);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::is_empty
//       Access: Published
//  Description: Returns true if no stages are defined in the
//               TexProjectorEffect, false if at least one is.
////////////////////////////////////////////////////////////////////
bool TexProjectorEffect::
is_empty() const {
  return _stages.empty();
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::has_stage
//       Access: Published
//  Description: Returns true if there is a transform associated with
//               the indicated stage, or false otherwise (in which
//               case get_transform(stage) will return the identity
//               transform).
////////////////////////////////////////////////////////////////////
bool TexProjectorEffect::
has_stage(TextureStage *stage) const {
  Stages::const_iterator mi = _stages.find(stage);
  return (mi != _stages.end());
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::get_from
//       Access: Published
//  Description: Returns the "from" node associated with the
//               TexProjectorEffect on the indicated stage.  The
//               relative transform between the "from" and the "to"
//               nodes is automatically applied to the texture
//               transform each frame.
////////////////////////////////////////////////////////////////////
NodePath TexProjectorEffect::
get_from(TextureStage *stage) const {
  Stages::const_iterator mi = _stages.find(stage);
  nassertr(mi != _stages.end(), NodePath::fail());
  return (*mi).second._from;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::get_to
//       Access: Published
//  Description: Returns the "to" node associated with the
//               TexProjectorEffect on the indicated stage.  The
//               relative transform between the "from" and the "to"
//               nodes is automatically applied to the texture
//               transform each frame.
//
//               Furthermore, if the "to" node is a LensNode, its
//               projection matrix is also applied to the texture
//               transform.
////////////////////////////////////////////////////////////////////
NodePath TexProjectorEffect::
get_to(TextureStage *stage) const {
  Stages::const_iterator mi = _stages.find(stage);
  nassertr(mi != _stages.end(), NodePath::fail());
  return (*mi).second._to;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::output
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
output(ostream &out) const {
  out << get_type() << ":";

  Stages::const_iterator mi;
  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
    TextureStage *stage = (*mi).first;
    const StageDef &def = (*mi).second;
    out << " " << stage->get_name() << "(" << def._to.get_name()
        << ", " << def._from.get_name() << ")";
  }
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::has_cull_callback
//       Access: Public, Virtual
//  Description: Should be overridden by derived classes to return
//               true if cull_callback() has been defined.  Otherwise,
//               returns false to indicate cull_callback() does not
//               need to be called for this effect during the cull
//               traversal.
////////////////////////////////////////////////////////////////////
bool TexProjectorEffect::
has_cull_callback() const {
  return !_stages.empty();
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::cull_callback
//       Access: Public, Virtual
//  Description: If has_cull_callback() returns true, this function
//               will be called during the cull traversal to perform
//               any additional operations that should be performed at
//               cull time.  This may include additional manipulation
//               of render state or additional visible/invisible
//               decisions, or any other arbitrary operation.
//
//               At the time this function is called, the current
//               node's transform and state have not yet been applied
//               to the net_transform and net_state.  This callback
//               may modify the node_transform and node_state to apply
//               an effective change to the render state at this
//               level.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
cull_callback(CullTraverser *trav, CullTraverserData &data,
              CPT(TransformState) &node_transform,
              CPT(RenderState) &node_state) const {
  CPT(TexMatrixAttrib) tex_matrix = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());

  Stages::const_iterator mi;
  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
    TextureStage *stage = (*mi).first;
    const StageDef &def = (*mi).second;

    CPT(TransformState) transform = def._from.get_transform(def._to);

    if (def._to_lens_node != (LensNode *)NULL &&
        def._to_lens_node->get_lens() != (Lens *)NULL) {

      // Get the lens's projection matrix, as a TransformState.
      CPT(TransformState) projmat = TransformState::make_mat(def._to_lens_node->get_lens()->get_projection_mat());

      // We need a special transform to convert the -0.5, 0.5
      // centering of the lens's projection matrix to UV's in the
      // range of (0, 1).
      static CPT(TransformState) fixmat;
      if (fixmat == (TransformState *)NULL) {
        fixmat = TransformState::make_pos_hpr_scale
          (LVecBase3f(0.5f, 0.5f, 0.0f),
           LVecBase3f(0.0f, 0.0f, 0.0f),
           LVecBase3f(0.5f, 0.5f, 1.0f));
      }

      // Now apply both to the current transform.
      transform = fixmat->compose(projmat)->compose(transform);
    }

    if (!transform->is_identity()) {
      tex_matrix = DCAST(TexMatrixAttrib,
                         tex_matrix->add_stage(stage, transform));
    }
  }

  if (!tex_matrix->is_empty()) {
    node_state = node_state->compose(RenderState::make(tex_matrix));
  }
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::compare_to_impl
//       Access: Protected, Virtual
//  Description: Intended to be overridden by derived TexProjectorEffect
//               types to return a unique number indicating whether
//               this TexProjectorEffect is equivalent to the other one.
//
//               This should return 0 if the two TexProjectorEffect objects
//               are equivalent, a number less than zero if this one
//               should be sorted before the other one, and a number
//               greater than zero otherwise.
//
//               This will only be called with two TexProjectorEffect
//               objects whose get_type() functions return the same.
////////////////////////////////////////////////////////////////////
int TexProjectorEffect::
compare_to_impl(const RenderEffect *other) const {
  const TexProjectorEffect *ta;
  DCAST_INTO_R(ta, other, 0);

  Stages::const_iterator ai, bi;
  ai = _stages.begin();
  bi = ta->_stages.begin();
  while (ai != _stages.end() && bi != ta->_stages.end()) {
    if ((*ai).first < (*bi).first) {
      // This stage is in a but not in b.
      return -1;

    } else if ((*bi).first < (*ai).first) {
      // This stage is in b but not in a.
      return 1;

    } else {
      // This stage is in both; compare the stages.
      int compare = (*ai).second.compare_to((*bi).second);
      if (compare != 0) {
        return compare;
      }
      ++ai;
      ++bi;
    }
  }

  if (bi != _stages.end()) {
    // a ran out first; b was longer.
    return -1;
  }

  if (ai != _stages.end()) {
    // b ran out first; a was longer.
    return 1;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::register_with_read_factory
//       Access: Public, Static
//  Description: Tells the BamReader how to create objects of type
//               TexProjectorEffect.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
register_with_read_factory() {
  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::write_datagram
//       Access: Public, Virtual
//  Description: Writes the contents of this object to the datagram
//               for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
write_datagram(BamWriter *manager, Datagram &dg) {
  RenderEffect::write_datagram(manager, dg);

  // For now, we don't write anything to the bam file for a
  // TexProjectorEffect, except a bogus 0 "size" which may one day
  // indicate the number of stages in the map that we might write out.
  dg.add_uint16(0);

  // One day we will write the whole map out.  We don't do this yet,
  // because (a) we don't have an interface for writing out NodePaths
  // to a bam file, and (b) it won't matter until we have the
  // Panda-monium system in place, since you can't load a
  // TexProjectorEffect from an egg file.
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::complete_pointers
//       Access: Public, Virtual
//  Description: Receives an array of pointers, one for each time
//               manager->read_pointer() was called in fillin().
//               Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int TexProjectorEffect::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
  int pi = RenderEffect::complete_pointers(p_list, manager);

  return pi;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::make_from_bam
//       Access: Protected, Static
//  Description: This function is called by the BamReader's factory
//               when a new object of type TexProjectorEffect is encountered
//               in the Bam file.  It should create the TexProjectorEffect
//               and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *TexProjectorEffect::
make_from_bam(const FactoryParams &params) {
  TexProjectorEffect *effect = new TexProjectorEffect;
  DatagramIterator scan;
  BamReader *manager;

  parse_params(params, scan, manager);
  effect->fillin(scan, manager);

  return effect;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::fillin
//       Access: Protected
//  Description: This internal function is called by make_from_bam to
//               read in all of the relevant data from the BamFile for
//               the new TexProjectorEffect.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
fillin(DatagramIterator &scan, BamReader *manager) {
  RenderEffect::fillin(scan, manager);

  size_t num_stages = scan.get_uint16();

  // Since we don't support full reading and writing of
  // TexProjectorEffects yet, this value had better be zero.  If it's
  // not, maybe we're trying to read a bam file that was generated by
  // some future version of Panda that does support these things.
  nassertv(num_stages == 0);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::StageDef::set_to
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::StageDef::
set_to(const NodePath &to) {
  _to = to;
  if (!_to.is_empty() && _to.node()->is_of_type(LensNode::get_class_type())) {
    DCAST_INTO_V(_to_lens_node, _to.node());
  } else {
    _to_lens_node = (LensNode *)NULL;
  }
}
<commit_msg>better output when one NodePath is empty<commit_after>// Filename: texProjectorEffect.cxx
// Created by:  drose (25Jul04)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license.  You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////

#include "texProjectorEffect.h"
#include "cullTraverserData.h"
#include "texMatrixAttrib.h"
#include "lensNode.h"
#include "config_pgraph.h"
#include "nodePath.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "datagram.h"
#include "datagramIterator.h"

CPT(RenderEffect) TexProjectorEffect::_empty_effect;
TypeHandle TexProjectorEffect::_type_handle;

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::Destructor
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
TexProjectorEffect::
~TexProjectorEffect() {
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::make
//       Access: Published, Static
//  Description: Constructs a TexProjectorEffect that modifies
//               no stages at all.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) TexProjectorEffect::
make() {
  // We make it a special case and store a pointer to the empty effect
  // forever once we find it the first time, as an optimization.
  if (_empty_effect == (RenderEffect *)NULL) {
    _empty_effect = return_new(new TexProjectorEffect);
  }

  return _empty_effect;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::add_stage
//       Access: Published, Static
//  Description: Returns a new TexProjectorEffect just like this one,
//               with the indicated projection for the given stage.
//               If this stage already exists, its projection
//               definition is replaced.
//
//               The relative transform between the "from" and the
//               "to" nodes is automatically applied to the texture
//               transform each frame.
//
//               Furthermore, if the "to" node is a LensNode, its
//               projection matrix is also applied to the texture
//               transform.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) TexProjectorEffect::
add_stage(TextureStage *stage, const NodePath &from, const NodePath &to) const {
  TexProjectorEffect *effect = new TexProjectorEffect(*this);
  StageDef &def = effect->_stages[stage];
  def.set_from(from);
  def.set_to(to);
  return return_new(effect);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::remove_stage
//       Access: Published, Static
//  Description: Returns a new TexProjectorEffect just like this one,
//               with the indicated stage removed.
////////////////////////////////////////////////////////////////////
CPT(RenderEffect) TexProjectorEffect::
remove_stage(TextureStage *stage) const {
  TexProjectorEffect *effect = new TexProjectorEffect(*this);
  effect->_stages.erase(stage);
  return return_new(effect);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::is_empty
//       Access: Published
//  Description: Returns true if no stages are defined in the
//               TexProjectorEffect, false if at least one is.
////////////////////////////////////////////////////////////////////
bool TexProjectorEffect::
is_empty() const {
  return _stages.empty();
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::has_stage
//       Access: Published
//  Description: Returns true if there is a transform associated with
//               the indicated stage, or false otherwise (in which
//               case get_transform(stage) will return the identity
//               transform).
////////////////////////////////////////////////////////////////////
bool TexProjectorEffect::
has_stage(TextureStage *stage) const {
  Stages::const_iterator mi = _stages.find(stage);
  return (mi != _stages.end());
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::get_from
//       Access: Published
//  Description: Returns the "from" node associated with the
//               TexProjectorEffect on the indicated stage.  The
//               relative transform between the "from" and the "to"
//               nodes is automatically applied to the texture
//               transform each frame.
////////////////////////////////////////////////////////////////////
NodePath TexProjectorEffect::
get_from(TextureStage *stage) const {
  Stages::const_iterator mi = _stages.find(stage);
  nassertr(mi != _stages.end(), NodePath::fail());
  return (*mi).second._from;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::get_to
//       Access: Published
//  Description: Returns the "to" node associated with the
//               TexProjectorEffect on the indicated stage.  The
//               relative transform between the "from" and the "to"
//               nodes is automatically applied to the texture
//               transform each frame.
//
//               Furthermore, if the "to" node is a LensNode, its
//               projection matrix is also applied to the texture
//               transform.
////////////////////////////////////////////////////////////////////
NodePath TexProjectorEffect::
get_to(TextureStage *stage) const {
  Stages::const_iterator mi = _stages.find(stage);
  nassertr(mi != _stages.end(), NodePath::fail());
  return (*mi).second._to;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::output
//       Access: Public, Virtual
//  Description:
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
output(ostream &out) const {
  out << get_type() << ":";

  Stages::const_iterator mi;
  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
    TextureStage *stage = (*mi).first;
    const StageDef &def = (*mi).second;
    out << " " << stage->get_name() << "(" << def._to
        << ", " << def._from << ")";
  }
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::has_cull_callback
//       Access: Public, Virtual
//  Description: Should be overridden by derived classes to return
//               true if cull_callback() has been defined.  Otherwise,
//               returns false to indicate cull_callback() does not
//               need to be called for this effect during the cull
//               traversal.
////////////////////////////////////////////////////////////////////
bool TexProjectorEffect::
has_cull_callback() const {
  return !_stages.empty();
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::cull_callback
//       Access: Public, Virtual
//  Description: If has_cull_callback() returns true, this function
//               will be called during the cull traversal to perform
//               any additional operations that should be performed at
//               cull time.  This may include additional manipulation
//               of render state or additional visible/invisible
//               decisions, or any other arbitrary operation.
//
//               At the time this function is called, the current
//               node's transform and state have not yet been applied
//               to the net_transform and net_state.  This callback
//               may modify the node_transform and node_state to apply
//               an effective change to the render state at this
//               level.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
cull_callback(CullTraverser *trav, CullTraverserData &data,
              CPT(TransformState) &node_transform,
              CPT(RenderState) &node_state) const {
  CPT(TexMatrixAttrib) tex_matrix = DCAST(TexMatrixAttrib, TexMatrixAttrib::make());

  Stages::const_iterator mi;
  for (mi = _stages.begin(); mi != _stages.end(); ++mi) {
    TextureStage *stage = (*mi).first;
    const StageDef &def = (*mi).second;

    CPT(TransformState) transform = def._from.get_transform(def._to);

    if (def._to_lens_node != (LensNode *)NULL &&
        def._to_lens_node->get_lens() != (Lens *)NULL) {

      // Get the lens's projection matrix, as a TransformState.
      CPT(TransformState) projmat = TransformState::make_mat(def._to_lens_node->get_lens()->get_projection_mat());

      // We need a special transform to convert the -0.5, 0.5
      // centering of the lens's projection matrix to UV's in the
      // range of (0, 1).
      static CPT(TransformState) fixmat;
      if (fixmat == (TransformState *)NULL) {
        fixmat = TransformState::make_pos_hpr_scale
          (LVecBase3f(0.5f, 0.5f, 0.0f),
           LVecBase3f(0.0f, 0.0f, 0.0f),
           LVecBase3f(0.5f, 0.5f, 1.0f));
      }

      // Now apply both to the current transform.
      transform = fixmat->compose(projmat)->compose(transform);
    }

    if (!transform->is_identity()) {
      tex_matrix = DCAST(TexMatrixAttrib,
                         tex_matrix->add_stage(stage, transform));
    }
  }

  if (!tex_matrix->is_empty()) {
    node_state = node_state->compose(RenderState::make(tex_matrix));
  }
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::compare_to_impl
//       Access: Protected, Virtual
//  Description: Intended to be overridden by derived TexProjectorEffect
//               types to return a unique number indicating whether
//               this TexProjectorEffect is equivalent to the other one.
//
//               This should return 0 if the two TexProjectorEffect objects
//               are equivalent, a number less than zero if this one
//               should be sorted before the other one, and a number
//               greater than zero otherwise.
//
//               This will only be called with two TexProjectorEffect
//               objects whose get_type() functions return the same.
////////////////////////////////////////////////////////////////////
int TexProjectorEffect::
compare_to_impl(const RenderEffect *other) const {
  const TexProjectorEffect *ta;
  DCAST_INTO_R(ta, other, 0);

  Stages::const_iterator ai, bi;
  ai = _stages.begin();
  bi = ta->_stages.begin();
  while (ai != _stages.end() && bi != ta->_stages.end()) {
    if ((*ai).first < (*bi).first) {
      // This stage is in a but not in b.
      return -1;

    } else if ((*bi).first < (*ai).first) {
      // This stage is in b but not in a.
      return 1;

    } else {
      // This stage is in both; compare the stages.
      int compare = (*ai).second.compare_to((*bi).second);
      if (compare != 0) {
        return compare;
      }
      ++ai;
      ++bi;
    }
  }

  if (bi != _stages.end()) {
    // a ran out first; b was longer.
    return -1;
  }

  if (ai != _stages.end()) {
    // b ran out first; a was longer.
    return 1;
  }

  return 0;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::register_with_read_factory
//       Access: Public, Static
//  Description: Tells the BamReader how to create objects of type
//               TexProjectorEffect.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
register_with_read_factory() {
  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::write_datagram
//       Access: Public, Virtual
//  Description: Writes the contents of this object to the datagram
//               for shipping out to a Bam file.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
write_datagram(BamWriter *manager, Datagram &dg) {
  RenderEffect::write_datagram(manager, dg);

  // For now, we don't write anything to the bam file for a
  // TexProjectorEffect, except a bogus 0 "size" which may one day
  // indicate the number of stages in the map that we might write out.
  dg.add_uint16(0);

  // One day we will write the whole map out.  We don't do this yet,
  // because (a) we don't have an interface for writing out NodePaths
  // to a bam file, and (b) it won't matter until we have the
  // Panda-monium system in place, since you can't load a
  // TexProjectorEffect from an egg file.
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::complete_pointers
//       Access: Public, Virtual
//  Description: Receives an array of pointers, one for each time
//               manager->read_pointer() was called in fillin().
//               Returns the number of pointers processed.
////////////////////////////////////////////////////////////////////
int TexProjectorEffect::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
  int pi = RenderEffect::complete_pointers(p_list, manager);

  return pi;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::make_from_bam
//       Access: Protected, Static
//  Description: This function is called by the BamReader's factory
//               when a new object of type TexProjectorEffect is encountered
//               in the Bam file.  It should create the TexProjectorEffect
//               and extract its information from the file.
////////////////////////////////////////////////////////////////////
TypedWritable *TexProjectorEffect::
make_from_bam(const FactoryParams &params) {
  TexProjectorEffect *effect = new TexProjectorEffect;
  DatagramIterator scan;
  BamReader *manager;

  parse_params(params, scan, manager);
  effect->fillin(scan, manager);

  return effect;
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::fillin
//       Access: Protected
//  Description: This internal function is called by make_from_bam to
//               read in all of the relevant data from the BamFile for
//               the new TexProjectorEffect.
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::
fillin(DatagramIterator &scan, BamReader *manager) {
  RenderEffect::fillin(scan, manager);

  size_t num_stages = scan.get_uint16();

  // Since we don't support full reading and writing of
  // TexProjectorEffects yet, this value had better be zero.  If it's
  // not, maybe we're trying to read a bam file that was generated by
  // some future version of Panda that does support these things.
  nassertv(num_stages == 0);
}

////////////////////////////////////////////////////////////////////
//     Function: TexProjectorEffect::StageDef::set_to
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
void TexProjectorEffect::StageDef::
set_to(const NodePath &to) {
  _to = to;
  if (!_to.is_empty() && _to.node()->is_of_type(LensNode::get_class_type())) {
    DCAST_INTO_V(_to_lens_node, _to.node());
  } else {
    _to_lens_node = (LensNode *)NULL;
  }
}
<|endoftext|>


<commit_before>#include <QDebug>
#include <QGraphicsEllipseItem>
#include <QGraphicsItem>
#include <QGraphicsTextItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QPen>
#include <QStyleOptionGraphicsItem>
#include <QVariant>
#include <QWidget>

#include <iostream>
#include <memory>
#include <cstdlib>

#include "gui/edge_graphics_item.h"
#include "gui/vertex_graphics_item.h"

VertexGraphicsItem::VertexGraphicsItem(Vertex *vertex, QGraphicsItem *parent)
    : QGraphicsEllipseItem(parent), vertex(vertex)
{
    setPen(QPen(QColor(90, 90, 90)));
    setFlag(QGraphicsItem::ItemIsMovable);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    setFlag(QGraphicsItem::ItemIsSelectable);
    setRect(0, 0, GraphicSize, GraphicSize);

    setX(vertex->x);
    setY(vertex->y);
    //    childItems().append();
}

QVariant VertexGraphicsItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemPositionChange) {
        repaintEdges();
    }
    return value;
}

void VertexGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mouseReleaseEvent(event);
    vertex->x = x();
    vertex->y = y();
    repaintEdges();
    qDebug() << "Released" << value();
}

void VertexGraphicsItem::repaintEdges()
{
    for (EdgeGraphicsItem *edge : edges) {
        edge->updatePosition();
    }
}

void VertexGraphicsItem::clearEdges() { edges.clear(); }

void VertexGraphicsItem::setCoordinates(float x, float y)
{
    setX(x);
    setY(y);
    vertex->x = x;
    vertex->y = y;
}

int VertexGraphicsItem::value() const { return vertex->value; }

bool VertexGraphicsItem::hasCoordinates() const
{
    return std::abs((long)x()) > 0.001 && std::abs((long)y()) > 0.001;
}

void VertexGraphicsItem::markSearch(bool value) {
    vertex->target = value;
//    vertex->color = value ? vertex_color::gray : vertex_color::white;
    update();
}

void VertexGraphicsItem::selected(bool value) {
    setSelected(value);
    vertex->selected = value;
}

void VertexGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    int opacity = vertex->selected ? 100 : 255;
    switch (vertex->color) {
    case vertex_color::white:
        setBrush(QBrush(QColor(120, 150, 130, opacity)));
        break;
    case vertex_color::gray:
        setBrush(QBrush(QColor(90, 100, 80, opacity)));
        break;
    case vertex_color::black:
        setBrush(QBrush(QColor(20, 50, 30, opacity)));
        break;
    }

    if (vertex->target) {
        QPen pen = QPen(QColor(100, 50, 50));
        pen.setWidth(2);
        setPen(pen);
    }

    QGraphicsEllipseItem::paint(painter, option, widget);

    QGraphicsTextItem text{};
    text.setHtml(QString("%1").arg(vertex->value));
    text.setFlag(QGraphicsItem::ItemIsSelectable, false);
    text.paint(painter, option, widget);
}
<commit_msg>Remove excessive logging of vertex mouse events<commit_after>#include <QDebug>
#include <QGraphicsEllipseItem>
#include <QGraphicsItem>
#include <QGraphicsTextItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <QPen>
#include <QStyleOptionGraphicsItem>
#include <QVariant>
#include <QWidget>

#include <iostream>
#include <memory>
#include <cstdlib>

#include "gui/edge_graphics_item.h"
#include "gui/vertex_graphics_item.h"

VertexGraphicsItem::VertexGraphicsItem(Vertex *vertex, QGraphicsItem *parent)
    : QGraphicsEllipseItem(parent), vertex(vertex)
{
    setPen(QPen(QColor(90, 90, 90)));
    setFlag(QGraphicsItem::ItemIsMovable);
    setFlag(QGraphicsItem::ItemSendsGeometryChanges);
    setFlag(QGraphicsItem::ItemIsSelectable);
    setRect(0, 0, GraphicSize, GraphicSize);

    setX(vertex->x);
    setY(vertex->y);
}

QVariant VertexGraphicsItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
    if (change == QGraphicsItem::ItemPositionChange) {
        repaintEdges();
    }
    return value;
}

void VertexGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    QGraphicsItem::mouseReleaseEvent(event);
    vertex->x = x();
    vertex->y = y();
    repaintEdges();
}

void VertexGraphicsItem::repaintEdges()
{
    for (EdgeGraphicsItem *edge : edges) {
        edge->updatePosition();
    }
}

void VertexGraphicsItem::clearEdges() { edges.clear(); }

void VertexGraphicsItem::setCoordinates(float x, float y)
{
    setX(x);
    setY(y);
    vertex->x = x;
    vertex->y = y;
}

int VertexGraphicsItem::value() const { return vertex->value; }

bool VertexGraphicsItem::hasCoordinates() const
{
    return std::abs((long)x()) > 0.001 && std::abs((long)y()) > 0.001;
}

void VertexGraphicsItem::markSearch(bool value) {
    vertex->target = value;
//    vertex->color = value ? vertex_color::gray : vertex_color::white;
    update();
}

void VertexGraphicsItem::selected(bool value) {
    setSelected(value);
    vertex->selected = value;
}

void VertexGraphicsItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    int opacity = vertex->selected ? 100 : 255;
    switch (vertex->color) {
    case vertex_color::white:
        setBrush(QBrush(QColor(120, 150, 130, opacity)));
        break;
    case vertex_color::gray:
        setBrush(QBrush(QColor(90, 100, 80, opacity)));
        break;
    case vertex_color::black:
        setBrush(QBrush(QColor(20, 50, 30, opacity)));
        break;
    }

    if (vertex->target) {
        QPen pen = QPen(QColor(100, 50, 50));
        pen.setWidth(2);
        setPen(pen);
    }

    QGraphicsEllipseItem::paint(painter, option, widget);

    QGraphicsTextItem text{};
    text.setHtml(QString("%1").arg(vertex->value));
    text.setFlag(QGraphicsItem::ItemIsSelectable, false);
    text.paint(painter, option, widget);
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mc/mc.C $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mc.C
/// @brief Subroutines to manipulate the memory controller
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/utils/dump_regs.H>
#include <lib/mc/mc.H>
#include <lib/utils/find.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;

namespace mss
{

///
/// @brief Dump the registers of the MC (MCA_MBA, MCS)
/// @param[in] i_target the MCS target
/// @return fapi2::FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode dump_regs( const fapi2::Target<TARGET_TYPE_MCS>& i_target )
{
    return fapi2::FAPI2_RC_SUCCESS;
}

namespace mc
{

///
/// @brief safemode throttle values defined from MRW attributes
/// @param[in] i_target the MCA target
/// @return fapi2::FAPI2_RC_SUCCESS if ok
/// @note sets safemode values for emergency mode and regular throttling
///
fapi2::ReturnCode thermal_throttle_scominit (const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    uint32_t l_throttle_denominator = 0;
    FAPI_TRY( mss::mem_m_dram_clocks( i_target, l_throttle_denominator) );

    {
        fapi2::buffer<uint64_t> l_data;
        FAPI_TRY(mss::getScom(i_target, MCA_MBA_FARB3Q, l_data));

        uint32_t l_throttle_per_port = 0;
        FAPI_TRY( mss::mrw_safemode_mem_throttled_n_commands_per_port( l_throttle_per_port) );

        l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_N_PER_SLOT, MCA_MBA_FARB3Q_CFG_NM_N_PER_SLOT_LEN>(l_throttle_per_port);
        l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_N_PER_PORT, MCA_MBA_FARB3Q_CFG_NM_N_PER_PORT_LEN>(l_throttle_per_port);
        l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_M, MCA_MBA_FARB3Q_CFG_NM_M_LEN>(l_throttle_denominator);

        l_data.clearBit<MCA_MBA_FARB3Q_CFG_NM_CHANGE_AFTER_SYNC>();

        FAPI_TRY( mss::putScom(i_target, MCA_MBA_FARB3Q, l_data) );
    }

    {
        fapi2::buffer<uint64_t> l_data;
        uint32_t l_throttle_per_slot = 0;

        FAPI_TRY( mss::mrw_safemode_mem_throttled_n_commands_per_port(l_throttle_per_slot) );
        FAPI_TRY( mss::getScom(i_target, MCA_MBA_FARB4Q, l_data) );

        l_data.insertFromRight<MCA_MBA_FARB4Q_EMERGENCY_M, MCA_MBA_FARB4Q_EMERGENCY_M_LEN>(l_throttle_denominator);
        l_data.insertFromRight<MCA_MBA_FARB4Q_EMERGENCY_N, MCA_MBA_FARB4Q_EMERGENCY_N_LEN>(l_throttle_per_slot);
        FAPI_TRY( mss::putScom(i_target, MCA_MBA_FARB4Q, l_data) );
    }

fapi_try_exit:
    return fapi2::current_err;
}

///
/// @brief Disable emergency mode throttle for thermal_init
/// @param[in] i_target the MCS target
/// @return fapi2::FAPI2_RC_SUCCESS if ok
/// @note Clears MCMODE0_ENABLE_EMER_THROTTLE bit in MCSMODE0
///
fapi2::ReturnCode disable_emergency_throttle (const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target)
{
    fapi2::buffer<uint64_t> l_data;

    FAPI_TRY( mss::getScom(i_target, MCS_MCMODE0, l_data));
    l_data.clearBit<MCS_MCMODE0_ENABLE_EMER_THROTTLE>();
    FAPI_TRY( mss::putScom(i_target, MCS_MCMODE0, l_data));

fapi_try_exit:
    return fapi2::current_err;
}

} // namespace mc

} //close namespace mss
<commit_msg>Power Thermal init<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/mc/mc.C $       */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file mc.C
/// @brief Subroutines to manipulate the memory controller
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Jacob Harvey <jlharvey@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/utils/dump_regs.H>
#include <lib/mc/mc.H>
#include <lib/utils/find.H>

using fapi2::TARGET_TYPE_MCA;
using fapi2::TARGET_TYPE_MCS;

namespace mss
{

///
/// @brief Dump the registers of the MC (MCA_MBA, MCS)
/// @param[in] i_target the MCS target
/// @return fapi2::FAPI2_RC_SUCCESS if ok
///
template<>
fapi2::ReturnCode dump_regs( const fapi2::Target<TARGET_TYPE_MCS>& i_target )
{
    return fapi2::FAPI2_RC_SUCCESS;
}

namespace mc
{

enum throttle_enums
{
    NM_RAS_WEIGHT = 0b000,
    NM_CAS_WEIGHT = 0b001,

    CHANGE_AFTER_SYNC = 0b1,

    MAXALL_MINALL = 0b000,
    //wait 16 refresh intervals of idle before powering down all ranks
    MIN_DOMAIN_REDUCTION_TIME = 0x10,
    //wait 64 refresh intervals of idle before going into STR on all ranks
    ENTER_STR_TIME = 0x40
};

///
/// @brief set the PWR CNTRL register
/// @param[in] i_target the mca target
/// @return fapi2::fapi2_rc_success if ok
/// @note sets MCA_MCA_MBARPC0Q
///
fapi2::ReturnCode set_pwr_cntrl_reg(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    uint8_t l_pwr_cntrl = 0;
    fapi2::buffer<uint64_t> l_data;

    FAPI_TRY(mrw_power_control_requested(l_pwr_cntrl));
    FAPI_TRY(mss::getScom(i_target, MCA_MBARPC0Q, l_data));

    l_data.insertFromRight<MCA_MBARPC0Q_CFG_MIN_MAX_DOMAINS, MCA_MBARPC0Q_CFG_MIN_MAX_DOMAINS_LEN>(MAXALL_MINALL);

    //Write data if PWR_CNTRL_REQUESTED includes power down
    l_data.writeBit<MCA_MBARPC0Q_CFG_MIN_DOMAIN_REDUCTION_ENABLE>
    ((l_pwr_cntrl == fapi2::ENUM_ATTR_MSS_MRW_POWER_CONTROL_REQUESTED_PD_AND_STR) ||
     (l_pwr_cntrl == fapi2::ENUM_ATTR_MSS_MRW_POWER_CONTROL_REQUESTED_POWER_DOWN));

    //Set the MIN_DOMAIN_REDUCTION time
    l_data.insertFromRight<MCA_MBARPC0Q_CFG_MIN_DOMAIN_REDUCTION_TIME, MCA_MBARPC0Q_CFG_MIN_DOMAIN_REDUCTION_TIME_LEN>
    (MIN_DOMAIN_REDUCTION_TIME);

    FAPI_TRY(mss::putScom(i_target, MCA_MBARPC0Q, l_data) );

    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    FAPI_ERR("Error setting power control register MBARPC0Q for target %s", mss::c_str(i_target));
    return fapi2::current_err;
}

///
/// @brief set the STR register
/// @param[in] i_target the mca target
/// @return fapi2::fapi2_rc_success if ok
/// @note sets MCA_MBASTR0Q
///
fapi2::ReturnCode set_str_reg(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    uint8_t l_str_enable = 0;
    fapi2::buffer<uint64_t> l_data;

    FAPI_TRY(mrw_power_control_requested(l_str_enable));
    FAPI_TRY(mss::getScom(i_target, MCA_MBASTR0Q, l_data));

    //Write bit if STR should be enabled
    l_data.writeBit<MCA_MBASTR0Q_CFG_STR_ENABLE>
    ((l_str_enable == fapi2::ENUM_ATTR_MSS_MRW_POWER_CONTROL_REQUESTED_STR) ||
     (l_str_enable == fapi2::ENUM_ATTR_MSS_MRW_POWER_CONTROL_REQUESTED_PD_AND_STR));

    l_data.insertFromRight<MCA_MBASTR0Q_CFG_ENTER_STR_TIME, MCA_MBASTR0Q_CFG_ENTER_STR_TIME_LEN>(ENTER_STR_TIME);

    FAPI_TRY(mss::putScom(i_target, MCA_MBASTR0Q, l_data) );

    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    FAPI_ERR("Error setting the STR register MBASTR0Q for target %s", mss::c_str(i_target));
    return fapi2::current_err;
}

///
/// @brief set the general N/M throttle register
/// @param[in] i_target the mca target
/// @return fapi2::fapi2_rc_success if ok
/// @note sets MCA_MBA_FARB3Q
///
fapi2::ReturnCode set_nm_support (const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    uint16_t l_run_slot = 0;
    uint16_t l_run_port = 0;
    uint32_t l_throttle_denominator = 0;

    fapi2::buffer<uint64_t> l_data;

    //runtime should be calculated in eff_config_thermal, which is called before scominit in ipl
    FAPI_TRY(runtime_mem_throttled_n_commands_per_port(i_target, l_run_port));
    FAPI_TRY(runtime_mem_throttled_n_commands_per_slot(i_target, l_run_slot));
    FAPI_TRY(mss::mrw_mem_m_dram_clocks(l_throttle_denominator) );
    FAPI_INF("For target %s throttled n commands per port are %d, per slot are %d, and dram m clocks are %d",
             mss::c_str(i_target),
             l_run_port,
             l_run_slot,
             l_throttle_denominator);
    FAPI_TRY(mss::getScom(i_target, MCA_MBA_FARB3Q, l_data));

    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_N_PER_SLOT, MCA_MBA_FARB3Q_CFG_NM_N_PER_SLOT_LEN>(l_run_slot);
    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_N_PER_PORT, MCA_MBA_FARB3Q_CFG_NM_N_PER_PORT_LEN>(l_run_port);
    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_M, MCA_MBA_FARB3Q_CFG_NM_M_LEN>(l_throttle_denominator);
    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_RAS_WEIGHT, MCA_MBA_FARB3Q_CFG_NM_RAS_WEIGHT_LEN>(NM_RAS_WEIGHT);
    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_CAS_WEIGHT, MCA_MBA_FARB3Q_CFG_NM_CAS_WEIGHT_LEN>(NM_CAS_WEIGHT);
    l_data.writeBit<MCA_MBA_FARB3Q_CFG_NM_CHANGE_AFTER_SYNC>(CHANGE_AFTER_SYNC);

    FAPI_TRY(mss::putScom(i_target, MCA_MBA_FARB3Q, l_data) );

    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    FAPI_ERR("Error setting nm throttles for target %s", mss::c_str(i_target));
    return fapi2::current_err;
}

///
/// @brief set the safemode throttle register
/// @param[in] i_target the mca target
/// @return fapi2::fapi2_rc_success if ok
/// @note sets MCA_MBA_FARB4Q
///
fapi2::ReturnCode set_safemode_throttles(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    fapi2::buffer<uint64_t> l_data;
    uint16_t l_throttle_per_slot = 0;
    uint32_t l_throttle_denominator = 0;

    FAPI_TRY(mss::mrw_mem_m_dram_clocks(l_throttle_denominator) );
    FAPI_TRY(mss::mrw_safemode_mem_throttled_n_commands_per_port(l_throttle_per_slot) );
    FAPI_TRY(mss::getScom(i_target, MCA_MBA_FARB4Q, l_data) );

    l_data.insertFromRight<MCA_MBA_FARB4Q_EMERGENCY_M, MCA_MBA_FARB4Q_EMERGENCY_M_LEN>(l_throttle_denominator);
    l_data.insertFromRight<MCA_MBA_FARB4Q_EMERGENCY_N, MCA_MBA_FARB4Q_EMERGENCY_N_LEN>(l_throttle_per_slot);
    FAPI_TRY(mss::putScom(i_target, MCA_MBA_FARB4Q, l_data) );
    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    FAPI_ERR("Error setting safemode throttles for target %s", mss::c_str(i_target));
    return fapi2::current_err;
}

///
/// @brief set the runtime throttle register to safemode values
/// @param[in] i_target the mca target
/// @return fapi2::fapi2_rc_success if ok
/// @note sets MCA_MBA_FARB3Q
/// @Will be overwritten by OCC/cronus later in IPL
/// @called in thermal_init
///
fapi2::ReturnCode set_runtime_throttles_to_safe(const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    fapi2::buffer<uint64_t> l_data;
    uint16_t l_throttle_per_port = 0;
    uint32_t l_throttle_denominator = 0;

    FAPI_TRY(mss::mrw_mem_m_dram_clocks(l_throttle_denominator) );
    FAPI_TRY(mss::mrw_safemode_mem_throttled_n_commands_per_port(l_throttle_per_port) );
    FAPI_TRY(mss::getScom(i_target, MCA_MBA_FARB3Q, l_data) );

    //Same value for both throttles
    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_N_PER_SLOT, MCA_MBA_FARB3Q_CFG_NM_N_PER_SLOT_LEN>(l_throttle_per_port);
    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_N_PER_PORT, MCA_MBA_FARB3Q_CFG_NM_N_PER_PORT_LEN>(l_throttle_per_port);
    l_data.insertFromRight<MCA_MBA_FARB3Q_CFG_NM_M, MCA_MBA_FARB3Q_CFG_NM_M_LEN>(l_throttle_denominator);

    FAPI_TRY(mss::putScom(i_target, MCA_MBA_FARB3Q, l_data) );
    return fapi2::FAPI2_RC_SUCCESS;

fapi_try_exit:
    FAPI_ERR("Error setting safemode throttles for target %s", mss::c_str(i_target));
    return fapi2::current_err;
}

///
/// @brief safemode throttle values defined from MRW attributes
/// @param[in] i_target the MCA target
/// @return fapi2::FAPI2_RC_SUCCESS if ok
/// @note sets safemode values for emergency mode and regular throttling
///
fapi2::ReturnCode thermal_throttle_scominit (const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target)
{
    FAPI_TRY(set_pwr_cntrl_reg(i_target));
    FAPI_TRY(set_str_reg(i_target));
    FAPI_TRY(set_nm_support(i_target));
    FAPI_TRY(set_safemode_throttles(i_target));

    return fapi2::FAPI2_RC_SUCCESS;
fapi_try_exit:
    FAPI_ERR("Error setting scominits for power_thermal values");
    return fapi2::current_err;
}

///
/// @brief disable emergency mode throttle for thermal_init
/// @param[in] i_target the mcs target
/// @return fapi2::fapi2_rc_success if ok
/// @note clears mcmode0_enable_emer_throttle bit in mcsmode0
///
fapi2::ReturnCode disable_emergency_throttle (const fapi2::Target<fapi2::TARGET_TYPE_MCS>& i_target)
{
    fapi2::buffer<uint64_t> l_data;

    FAPI_TRY(mss::getScom(i_target, MCS_MCMODE0, l_data));
    l_data.clearBit<MCS_MCMODE0_ENABLE_EMER_THROTTLE>();
    FAPI_TRY(mss::putScom(i_target, MCS_MCMODE0, l_data));

fapi_try_exit:
    return fapi2::current_err;
}

} // namespace mc

} //close namespace mss
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdeclarativebluetoothsocket_p.h"

#include <QPointer>
#include <QStringList>
#include <QDataStream>
#include <QByteArray>

#include <qbluetoothdeviceinfo.h>
#include <qbluetoothaddress.h>
#include <qbluetoothsocket.h>
#include <ql2capserver.h>
#include <qrfcommserver.h>

/* ==================== QDeclarativeBluetoothSocket ======================= */

/*!
   \qmlclass BluetoothSocket QDeclarativeBluetoothSocket
   \brief Enables you to connect and communicate with a Bluetooth service or device.

   \ingroup bluetooth-qml
   \inmodule QtBluetooth

   \sa QBluetoothSocket
   \sa QDataStream

    The BluetoothSocket type was introduced in \b{QtBluetooth 5.0}.

    It allows a QML class connect to another bluetooth device and send
    and receive QString from the device. Data is sent and received using a
    QDataStream object allowing type safe transfer of string data. QDataStream
    is a well known format and can be decoded by non-Qt applications.

    Connections to remote devices can be over rfcomm or l2cap.  Either the remote port
    or service UUID is required.  This is specified by creating a BluetoothService,
    or passing in the service return from BluetoothDiscoveryModel.
 */

class QDeclarativeBluetoothSocketPrivate
{
public:
    QDeclarativeBluetoothSocketPrivate(QDeclarativeBluetoothSocket *bs)
        : m_dbs(bs), m_service(0), m_socket(0),
          m_error(QLatin1String("No Error")),
          m_state(QLatin1String("No Service Set")),
          m_componentCompleted(false),
          m_connected(false)
    {

    }

    ~QDeclarativeBluetoothSocketPrivate()
    {
        delete m_socket;
    }

    void connect()
    {
        Q_ASSERT(m_service);
        qDebug() << "Connecting to: " << m_service->serviceInfo()->device().address().toString();
        m_error = QLatin1String("No Error");

        if (m_socket)
            m_socket->deleteLater();

//        delete m_socket;
        m_socket = new QBluetoothSocket();
        m_socket->connectToService(*m_service->serviceInfo());
        QObject::connect(m_socket, SIGNAL(connected()), m_dbs, SLOT(socket_connected()));
        QObject::connect(m_socket, SIGNAL(disconnected()), m_dbs, SLOT(socket_disconnected()));
        QObject::connect(m_socket, SIGNAL(error(QBluetoothSocket::SocketError)), m_dbs, SLOT(socket_error(QBluetoothSocket::SocketError)));
        QObject::connect(m_socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), m_dbs, SLOT(socket_state(QBluetoothSocket::SocketState)));
        QObject::connect(m_socket, SIGNAL(readyRead()), m_dbs, SLOT(socket_readyRead()));

        m_stream = new QDataStream(m_socket);
    }

    QDeclarativeBluetoothSocket *m_dbs;
    QDeclarativeBluetoothService *m_service;
    QBluetoothSocket *m_socket;
    QString m_error;
    QString m_state;
    bool m_componentCompleted;
    bool m_connected;
    QDataStream *m_stream;

};

QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QObject *parent) :
    QObject(parent)
{
    d = new QDeclarativeBluetoothSocketPrivate(this);
}

QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QDeclarativeBluetoothService *service, QObject *parent)
    : QObject(parent)
{
    d = new QDeclarativeBluetoothSocketPrivate(this);
    d->m_service = service;
}

QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service, QObject *parent)
    : QObject(parent)
{
    d = new QDeclarativeBluetoothSocketPrivate(this);
    d->m_service = service;
    d->m_socket = socket;
    d->m_connected = true;
    d->m_componentCompleted = true;

    QObject::connect(socket, SIGNAL(connected()), this, SLOT(socket_connected()));
    QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
    QObject::connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socket_error(QBluetoothSocket::SocketError)));
    QObject::connect(socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(socket_state(QBluetoothSocket::SocketState)));
    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(socket_readyRead()));

    d->m_stream = new QDataStream(socket);

}

QDeclarativeBluetoothSocket::~QDeclarativeBluetoothSocket()
{
    delete d;
}

void QDeclarativeBluetoothSocket::componentComplete()
{
    d->m_componentCompleted = true;

    if (d->m_connected && d->m_service)
        d->connect();
}

/*!
  \qmlproperty BluetoothService BluetoothSocket::service

  This property holds the details of the remote service to connect to. It can be
  set to a static BluetoothService with a fixed description, or a service returned
  by service discovery.
  */

QDeclarativeBluetoothService *QDeclarativeBluetoothSocket::service()
{
    return d->m_service;
}

void QDeclarativeBluetoothSocket::setService(QDeclarativeBluetoothService *service)
{
    d->m_service = service;

    if (!d->m_componentCompleted)
        return;

    if (d->m_connected)
        d->connect();
    emit serviceChanged();
}

/*!
  \qmlproperty bool BluetoothSocket::connected

  This property holds the connection state of the socket. If the socket is
  connected to peer, it returns true. It can be set true or false to control the
  connection. When set to true, the property will not return true until the
  connection is established.

  */

bool QDeclarativeBluetoothSocket::connected()
{
    if (!d->m_socket)
        return false;

    return d->m_socket->state() == QBluetoothSocket::ConnectedState;
}

void QDeclarativeBluetoothSocket::setConnected(bool connected)
{
    d->m_connected = connected;
    if (connected && d->m_componentCompleted) {
        if (d->m_service) {
            d->connect();
        }
        else {
            qWarning() << "BluetoothSocket::setConnected called before a service was set";
        }
    }

    if (!connected && d->m_socket){
        d->m_socket->close();
    }
}

/*!
  \qmlproperty string BluetoothSocket::error

  This property holds the string for the last reported error
  This property is read-only.
  */

QString QDeclarativeBluetoothSocket::error()
{
    return d->m_error;
}

void QDeclarativeBluetoothSocket::socket_connected()
{
    emit connectedChanged();
}

void QDeclarativeBluetoothSocket::socket_disconnected()
{
    d->m_socket->deleteLater();
    d->m_socket = 0;
    emit connectedChanged();
}

void QDeclarativeBluetoothSocket::socket_error(QBluetoothSocket::SocketError err)
{
    if (err == QBluetoothSocket::ConnectionRefusedError)
        d->m_error = QLatin1String("Connection Refused");
    else if (err == QBluetoothSocket::RemoteHostClosedError)
        d->m_error = QLatin1String("Connection Closed by Remote Host");
    else if (err == QBluetoothSocket::HostNotFoundError)
        d->m_error = QLatin1String("Host Not Found");
    else if (err == QBluetoothSocket::ServiceNotFoundError)
        d->m_error = QLatin1String("Could not find service at remote host");
    else
        d->m_error = QLatin1String("Unknown Error");

    emit errorChanged();
}

void QDeclarativeBluetoothSocket::socket_state(QBluetoothSocket::SocketState state)
{
    switch (state) {
    case QBluetoothSocket::UnconnectedState:
        d->m_state = QLatin1String("Unconnected");
        break;
    case QBluetoothSocket::ServiceLookupState:
        d->m_state = QLatin1String("Service Lookup");
        break;
    case QBluetoothSocket::ConnectingState:
        d->m_state = QLatin1String("Connecting");
        break;
    case QBluetoothSocket::ConnectedState:
        d->m_state = QLatin1String("Connected");
        break;
    case QBluetoothSocket::ClosingState:
        d->m_state = QLatin1String("Closing");
        break;
    case QBluetoothSocket::ListeningState:
        d->m_state = QLatin1String("Listening");
        break;
    case QBluetoothSocket::BoundState:
        d->m_state = QLatin1String("Bound");
        break;
    }

    emit stateChanged();
}

QString QDeclarativeBluetoothSocket::state()
{
    return d->m_state;
}

void QDeclarativeBluetoothSocket::socket_readyRead()
{
    emit dataAvailable();
}

/*!
  \qmlproperty string BluetoothSocket::stringData

  This property receives or sends data to remote bluetooth device. Arrival of
  data is signaled by the dataAvailable signal and can be read by
  stringData. Calling sendStringData will transmit the string.
  If excessive amounts of data are sent, the function may block sending. Reading will
  never block.
  */

QString QDeclarativeBluetoothSocket::stringData()
{
    if (!d->m_socket|| !d->m_socket->bytesAvailable())
        return QString();

    QString data;
    *d->m_stream >> data;
    return data;
}

void QDeclarativeBluetoothSocket::sendStringData(QString data)
{
    if (!d->m_connected || !d->m_socket){
        qWarning() << "Writing data to unconnected socket";
        return;
    }

    QByteArray b;
    QDataStream s(&b, QIODevice::WriteOnly);
    s << data;
    d->m_socket->write(b);
}

void QDeclarativeBluetoothSocket::newSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service)
{
    if (d->m_socket){
        delete d->m_socket;
    }

    d->m_service = service;
    d->m_socket = socket;
    d->m_connected = true;
    d->m_componentCompleted = true;
    d->m_error = QLatin1String("No Error");

    QObject::connect(socket, SIGNAL(connected()), this, SLOT(socket_connected()));
    QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
    QObject::connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socket_error(QBluetoothSocket::SocketError)));
    QObject::connect(socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(socket_state(QBluetoothSocket::SocketState)));
    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(socket_readyRead()));

    d->m_stream = new QDataStream(socket);

    socket_state(socket->state());

    emit connectedChanged();
}
<commit_msg>improve BluetoothSocket docs<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtBluetooth module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qdeclarativebluetoothsocket_p.h"

#include <QPointer>
#include <QStringList>
#include <QDataStream>
#include <QByteArray>

#include <qbluetoothdeviceinfo.h>
#include <qbluetoothaddress.h>
#include <qbluetoothsocket.h>
#include <ql2capserver.h>
#include <qrfcommserver.h>

/* ==================== QDeclarativeBluetoothSocket ======================= */

/*!
   \qmlclass BluetoothSocket QDeclarativeBluetoothSocket
   \brief Enables you to connect and communicate with a Bluetooth service or device.

   \ingroup bluetooth-qml
   \inmodule QtBluetooth

   \sa QBluetoothSocket
   \sa QDataStream

    The BluetoothSocket type was introduced in \b{QtBluetooth 5.0}.

    It allows a QML class connect to another Bluetooth device and exchange strings
    with it. Data is sent and received using a QDataStream object allowing type
    safe transfers of QStrings. QDataStream is a well known format and can be
    decoded by non-Qt applications. Note that for the ease of use, BluetoothSocket
    is only well suited for use with strings. If you want to
    use a binary protocol for your application's communication you should
    consider using its C++ counterpart QBluetoothSocket.

    Connections to remote devices can be over RFCOMM or L2CAP.  Either the remote port
    or service UUID is required.  This is specified by creating a BluetoothService,
    or passing in the service return from BluetoothDiscoveryModel.
 */

class QDeclarativeBluetoothSocketPrivate
{
public:
    QDeclarativeBluetoothSocketPrivate(QDeclarativeBluetoothSocket *bs)
        : m_dbs(bs), m_service(0), m_socket(0),
          m_error(QLatin1String("No Error")),
          m_state(QLatin1String("No Service Set")),
          m_componentCompleted(false),
          m_connected(false)
    {

    }

    ~QDeclarativeBluetoothSocketPrivate()
    {
        delete m_socket;
    }

    void connect()
    {
        Q_ASSERT(m_service);
        qDebug() << "Connecting to: " << m_service->serviceInfo()->device().address().toString();
        m_error = QLatin1String("No Error");

        if (m_socket)
            m_socket->deleteLater();

//        delete m_socket;
        m_socket = new QBluetoothSocket();
        m_socket->connectToService(*m_service->serviceInfo());
        QObject::connect(m_socket, SIGNAL(connected()), m_dbs, SLOT(socket_connected()));
        QObject::connect(m_socket, SIGNAL(disconnected()), m_dbs, SLOT(socket_disconnected()));
        QObject::connect(m_socket, SIGNAL(error(QBluetoothSocket::SocketError)), m_dbs, SLOT(socket_error(QBluetoothSocket::SocketError)));
        QObject::connect(m_socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), m_dbs, SLOT(socket_state(QBluetoothSocket::SocketState)));
        QObject::connect(m_socket, SIGNAL(readyRead()), m_dbs, SLOT(socket_readyRead()));

        m_stream = new QDataStream(m_socket);
    }

    QDeclarativeBluetoothSocket *m_dbs;
    QDeclarativeBluetoothService *m_service;
    QBluetoothSocket *m_socket;
    QString m_error;
    QString m_state;
    bool m_componentCompleted;
    bool m_connected;
    QDataStream *m_stream;

};

QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QObject *parent) :
    QObject(parent)
{
    d = new QDeclarativeBluetoothSocketPrivate(this);
}

QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QDeclarativeBluetoothService *service, QObject *parent)
    : QObject(parent)
{
    d = new QDeclarativeBluetoothSocketPrivate(this);
    d->m_service = service;
}

QDeclarativeBluetoothSocket::QDeclarativeBluetoothSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service, QObject *parent)
    : QObject(parent)
{
    d = new QDeclarativeBluetoothSocketPrivate(this);
    d->m_service = service;
    d->m_socket = socket;
    d->m_connected = true;
    d->m_componentCompleted = true;

    QObject::connect(socket, SIGNAL(connected()), this, SLOT(socket_connected()));
    QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
    QObject::connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socket_error(QBluetoothSocket::SocketError)));
    QObject::connect(socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(socket_state(QBluetoothSocket::SocketState)));
    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(socket_readyRead()));

    d->m_stream = new QDataStream(socket);

}

QDeclarativeBluetoothSocket::~QDeclarativeBluetoothSocket()
{
    delete d;
}

void QDeclarativeBluetoothSocket::componentComplete()
{
    d->m_componentCompleted = true;

    if (d->m_connected && d->m_service)
        d->connect();
}

/*!
  \qmlproperty BluetoothService BluetoothSocket::service

  This property holds the details of the remote service to connect to. It can be
  set to a static BluetoothService with a fixed description, or a service returned
  by service discovery.
  */

QDeclarativeBluetoothService *QDeclarativeBluetoothSocket::service()
{
    return d->m_service;
}

void QDeclarativeBluetoothSocket::setService(QDeclarativeBluetoothService *service)
{
    d->m_service = service;

    if (!d->m_componentCompleted)
        return;

    if (d->m_connected)
        d->connect();
    emit serviceChanged();
}

/*!
  \qmlproperty bool BluetoothSocket::connected

  This property holds the connection state of the socket. If the socket is
  connected to peer, it returns true. It can be set true or false to control the
  connection. When set to true, the property will not return true until the
  connection is established.

  */

bool QDeclarativeBluetoothSocket::connected()
{
    if (!d->m_socket)
        return false;

    return d->m_socket->state() == QBluetoothSocket::ConnectedState;
}

void QDeclarativeBluetoothSocket::setConnected(bool connected)
{
    d->m_connected = connected;
    if (connected && d->m_componentCompleted) {
        if (d->m_service) {
            d->connect();
        }
        else {
            qWarning() << "BluetoothSocket::setConnected called before a service was set";
        }
    }

    if (!connected && d->m_socket){
        d->m_socket->close();
    }
}

/*!
  \qmlproperty string BluetoothSocket::error

  This property holds the string for the last reported error
  This property is read-only.
  */

QString QDeclarativeBluetoothSocket::error()
{
    return d->m_error;
}

void QDeclarativeBluetoothSocket::socket_connected()
{
    emit connectedChanged();
}

void QDeclarativeBluetoothSocket::socket_disconnected()
{
    d->m_socket->deleteLater();
    d->m_socket = 0;
    emit connectedChanged();
}

void QDeclarativeBluetoothSocket::socket_error(QBluetoothSocket::SocketError err)
{
    if (err == QBluetoothSocket::ConnectionRefusedError)
        d->m_error = QLatin1String("Connection Refused");
    else if (err == QBluetoothSocket::RemoteHostClosedError)
        d->m_error = QLatin1String("Connection Closed by Remote Host");
    else if (err == QBluetoothSocket::HostNotFoundError)
        d->m_error = QLatin1String("Host Not Found");
    else if (err == QBluetoothSocket::ServiceNotFoundError)
        d->m_error = QLatin1String("Could not find service at remote host");
    else
        d->m_error = QLatin1String("Unknown Error");

    emit errorChanged();
}

void QDeclarativeBluetoothSocket::socket_state(QBluetoothSocket::SocketState state)
{
    switch (state) {
    case QBluetoothSocket::UnconnectedState:
        d->m_state = QLatin1String("Unconnected");
        break;
    case QBluetoothSocket::ServiceLookupState:
        d->m_state = QLatin1String("Service Lookup");
        break;
    case QBluetoothSocket::ConnectingState:
        d->m_state = QLatin1String("Connecting");
        break;
    case QBluetoothSocket::ConnectedState:
        d->m_state = QLatin1String("Connected");
        break;
    case QBluetoothSocket::ClosingState:
        d->m_state = QLatin1String("Closing");
        break;
    case QBluetoothSocket::ListeningState:
        d->m_state = QLatin1String("Listening");
        break;
    case QBluetoothSocket::BoundState:
        d->m_state = QLatin1String("Bound");
        break;
    }

    emit stateChanged();
}

QString QDeclarativeBluetoothSocket::state()
{
    return d->m_state;
}

void QDeclarativeBluetoothSocket::socket_readyRead()
{
    emit dataAvailable();
}

/*!
  \qmlproperty string BluetoothSocket::stringData

  This property receives or sends data to remote Bluetooth device. Arrival of
  data is signaled by the dataAvailable signal and can be read by
  stringData. Calling sendStringData will transmit the string.
  If excessive amounts of data are sent, the function may block sending. Reading will
  never block.
  */

QString QDeclarativeBluetoothSocket::stringData()
{
    if (!d->m_socket|| !d->m_socket->bytesAvailable())
        return QString();

    QString data;
    *d->m_stream >> data;
    return data;
}

void QDeclarativeBluetoothSocket::sendStringData(QString data)
{
    if (!d->m_connected || !d->m_socket){
        qWarning() << "Writing data to unconnected socket";
        return;
    }

    QByteArray b;
    QDataStream s(&b, QIODevice::WriteOnly);
    s << data;
    d->m_socket->write(b);
}

void QDeclarativeBluetoothSocket::newSocket(QBluetoothSocket *socket, QDeclarativeBluetoothService *service)
{
    if (d->m_socket){
        delete d->m_socket;
    }

    d->m_service = service;
    d->m_socket = socket;
    d->m_connected = true;
    d->m_componentCompleted = true;
    d->m_error = QLatin1String("No Error");

    QObject::connect(socket, SIGNAL(connected()), this, SLOT(socket_connected()));
    QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
    QObject::connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socket_error(QBluetoothSocket::SocketError)));
    QObject::connect(socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(socket_state(QBluetoothSocket::SocketState)));
    QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(socket_readyRead()));

    d->m_stream = new QDataStream(socket);

    socket_state(socket->state());

    emit connectedChanged();
}
<|endoftext|>


<commit_before>#include "mathutils.h"

#include <cstdlib>
#include <cstring>
#include <cmath>

bool intersects(const vec2f& circle, const real32 radius, const vec2f& min, const vec2f& max)
{
    const vec2f closest = vec2f::clamp(circle, min, max);
    const vec2f delta = circle - closest;

    const float distanceSquared = (delta.x * delta.x) + (delta.y * delta.y);
    const float radiusSquared = radius * radius;

    return distanceSquared < radiusSquared;
}

bool intersects(const vec2f& circleA, const real32 radiusA, const vec2f& circleB, const real32 radiusB)
{
    const vec2f distance = circleA - circleB;
    const real32 distanceSq = vec2f::dot(distance, distance);

    return !(distanceSq > ((radiusA + radiusB) * (radiusA + radiusB)));
}

real32 randomFloat(real32 min, real32 max)
{
    const real32 range = (max-min) + 1.0f;
    return min + (range * rand() / (RAND_MAX + 1.0f));
}

vec2f closestCirclePoint(const vec2f& center, const real32 radius, const vec2f& point)
{
    const vec2f v = point - center;
    const real32 len = 1.0f / v.length();

    return vec2f(center.x + (v.x * len) * radius, center.y + (v.y * len) * radius);
}

real32 normalize(real32 value, const real32 min, const real32 max)
{
    return (value - min) / (max - min);
}

real32** createMatrix(const uint32 width, const uint32 height)
{
    real32** matrix = new real32*[width];

    for (uint32 x = 0; x < width; x++)
    {
        matrix[x] = new real32[height];
    }

    for (uint32 x = 0; x < width; x++)
    {
        std::memset(matrix[x], 0, height);
    }

    return matrix;
}

void deleteMatrix(real32** matrix, const uint32 width)
{
    for (int x = 0; x < width; x++)
    {
        delete [] matrix[x];
    }

    delete [] matrix;
}
<commit_msg>Fixed an issue with the random method not generating the correct range.<commit_after>#include "mathutils.h"

#include <cstdlib>
#include <cstring>
#include <cmath>

bool intersects(const vec2f& circle, const real32 radius, const vec2f& min, const vec2f& max)
{
    const vec2f closest = vec2f::clamp(circle, min, max);
    const vec2f delta = circle - closest;

    const float distanceSquared = (delta.x * delta.x) + (delta.y * delta.y);
    const float radiusSquared = radius * radius;

    return distanceSquared < radiusSquared;
}

bool intersects(const vec2f& circleA, const real32 radiusA, const vec2f& circleB, const real32 radiusB)
{
    const vec2f distance = circleA - circleB;
    const real32 distanceSq = vec2f::dot(distance, distance);

    return !(distanceSq > ((radiusA + radiusB) * (radiusA + radiusB)));
}

real32 randomFloat(real32 min, real32 max)
{
    const real32 range = (max-min);
    return min + (range * rand() / (RAND_MAX + 1.0f));
}

vec2f closestCirclePoint(const vec2f& center, const real32 radius, const vec2f& point)
{
    const vec2f v = point - center;
    const real32 len = 1.0f / v.length();

    return vec2f(center.x + (v.x * len) * radius, center.y + (v.y * len) * radius);
}

real32 normalize(real32 value, const real32 min, const real32 max)
{
    return (value - min) / (max - min);
}

//TODO: (Tyler) Convert this into the proper std::pointer

real32** createMatrix(const uint32 width, const uint32 height)
{
    real32** matrix = new real32*[width];

    for (uint32 x = 0; x < width; x++)
    {
        matrix[x] = new real32[height];
    }

    for (uint32 x = 0; x < width; x++)
    {
        std::memset(matrix[x], 0, height);
    }

    return matrix;
}

void deleteMatrix(real32** matrix, const uint32 width)
{
    for (int x = 0; x < width; x++)
    {
        delete [] matrix[x];
    }

    delete [] matrix;
}
<|endoftext|>


<commit_before>#include "app.h"

#include <chrono>
#include <thread>
#include <algorithm>
#include <fstream>

using namespace std;

App::App(
    Settings settings,
    std::unique_ptr<FileManagerInterface> fileManager,
    std::unique_ptr<P2PNetworkInterface> networkManager) :
    settings(settings),
    fileManager(std::move(fileManager)),
    networkManager(std::move(networkManager)) {

    this->networkManager->setPorts(
        settings.ms_port,
        settings.server_port,
        settings.file_mgr_port);
}

void App::run() {
    running = true;
    networkManager->start(settings.main_server);

    fileMgrThread = new std::thread(&FileManagerInterface::run, &*fileManager);

    appThread = new std::thread(&App::listener, this);
}

void App::stop() {
    running = false;

    fileMgrThread->join();
    delete fileMgrThread;

    appThread->join();
    delete appThread;

    fileManager->stop();
    networkManager->stop();
}

App::~App() {
    stop();
}

void App::listener() {
    // bind, listen on settings.app_port and return fileManager->myIds();
    // stop when this->running == false
}

App::host_id_map App::getPeersIds() {
    // connect to all networkManager->get_peers():settings.app_port and get their ids
    return host_id_map();
}

namespace {
    vector<string> split(const string & str, const string & delimiter) {
        std::remove_const<decltype(string::npos)>::type start = 0, end = 0;
        vector<string> output;
        while ((end = str.find(delimiter, start)) != string::npos) {
            output.push_back(str.substr(start, end - start));
            start = end + 1;
        }
        output.push_back(str.substr(start));
        return output;
    }

    vector<string> fixPeers(const vector<PeerInfo> & inputPeers) {
        vector<string> fixedPeers;
        for (const auto & peer : inputPeers) {
            const auto parts = split(peer.address, "/");
            fixedPeers.push_back(parts[0] + ":" + parts.back());
        }
        return fixedPeers;
    }

    //TODO: make cleaner impl, maybe move to fileManager?
    std::vector<App::FileInfo> chunkifyFile(const std::string & filePath) {
        std::ifstream file(filePath, std::ios::in | std::ios::binary);
        if (!file) {
            return {};
        }
        file.seekg(0, std::ios::end);
        uint64_t size = file.tellg();
        file.close();

        std::vector<App::FileInfo> chunks;

        uint64_t c = 0;
        // push chunks with size App::fileChunkSize
        for (; size >= App::fileChunkSize; c += App::fileChunkSize) {
            chunks.push_back({ c, App::fileChunkSize, {} });
            size -= App::fileChunkSize;
        }

        // if there is more of the file, make it last chunk
        if (size > 0) {
            chunks.push_back({ c, size, {} });
        }

        return chunks;
    }
}

bool App::importFile(const std::string & filePath) {
    if (storage.find(filePath) != storage.end()) {
        return false;
    }

    auto peers = fixPeers(networkManager->get_peers());

	if (!peers.size()) {
		return false;
	}

    std::vector<FileInfo> fileChunks = chunkifyFile(filePath);

	auto peerIter = peers.cbegin();

    // circular iterator over std::vector
    auto next = [](decltype(peerIter) & iter, decltype(peers) & container) {
        if (++iter == container.end()) {
            iter = container.begin();
        }
    };

    for (auto & chunk : fileChunks) {

        for (int c = 0; c < static_cast<int>(FileAvailability::High); ++c) {
            uint64_t sentChunkId = fileManager->send(*peerIter, filePath, chunk.start, chunk.start + chunk.size);

            if (sentChunkId == 0) {
                break;
            } else {
                chunk.hosts.push_back(make_pair(*peerIter, sentChunkId));
            }
        }

        next(peerIter, peers);
    }

    storage[filePath] = fileChunks;
    return true;
}

App::FileAvailability App::isFileInStorage(const std::string & filePath) {
    auto file = storage.find(filePath);
    if (file == storage.end()) {
        return FileAvailability::None;
    }

    const auto & peers = networkManager->get_peers();

	if (!peers.size()){
		return FileAvailability::None;
	}

    FileAvailability fileStatus = FileAvailability::High;

    // Go trough all of the chunks and check which of them has least connected hosts
    for (auto & chunk : file->second) {
        int currentChunk = 0;
        for (auto & host : chunk.hosts) {
            currentChunk +=
                std::any_of(peers.begin(), peers.end(), [&host](const PeerInfo & info) {
                    const auto & parts = split(info.address, "/");
                    const auto & peerAddress = parts[0] + ":" + parts.back();

                    return peerAddress == host.first && info.connected;
                });
        }
        fileStatus = static_cast<FileAvailability>(
            std::min<int>(currentChunk, static_cast<int>(fileStatus)));
    }

    return fileStatus;
}

bool App::exportFile(const std::string & storageFile, const std::string & outputFilePath) {
    auto file = storage.find(storageFile);
    if (file == storage.end()) {
        return false;
    }

    ofstream outputFile(outputFilePath, ios::trunc | ios::binary);
    if (!outputFile) {
        return false;
    }

    for (const auto & chunk : file->second) {
        bool gotChunk = false;
        for (const auto & chunkLocation : chunk.hosts) {
            auto data = fileManager->getFile(chunkLocation.first, chunkLocation.second);
            if (data) {
                gotChunk = true;
                if (!outputFile.write(data.get(), chunk.size)) {
                    return false;
                }
                break; // all good chink written to file
            }

        }
        if (!gotChunk) {
            return false;
        }
    }

    return true;
}
<commit_msg>Add app debug messages<commit_after>#include "app.h"

#include <chrono>
#include <thread>
#include <algorithm>
#include <numeric>
#include <string>
#include <fstream>
#include <iostream>

using namespace std;

App::App(
    Settings settings,
    std::unique_ptr<FileManagerInterface> fileManager,
    std::unique_ptr<P2PNetworkInterface> networkManager) :
    settings(settings),
    fileManager(std::move(fileManager)),
    networkManager(std::move(networkManager)) {

    this->networkManager->setPorts(
        settings.ms_port,
        settings.server_port,
        settings.file_mgr_port);
}

void App::run() {
    running = true;
    networkManager->start(settings.main_server);

    fileMgrThread = new std::thread(&FileManagerInterface::run, &*fileManager);

    appThread = new std::thread(&App::listener, this);
}

void App::stop() {
    running = false;

    fileMgrThread->join();
    delete fileMgrThread;

    appThread->join();
    delete appThread;

    fileManager->stop();
    networkManager->stop();
}

App::~App() {
    stop();
}

void App::listener() {
    // bind, listen on settings.app_port and return fileManager->myIds();
    // stop when this->running == false
}

App::host_id_map App::getPeersIds() {
    // connect to all networkManager->get_peers():settings.app_port and get their ids
    return host_id_map();
}

namespace {
    vector<string> split(const string & str, const string & delimiter) {
        std::remove_const<decltype(string::npos)>::type start = 0, end = 0;
        vector<string> output;
        while ((end = str.find(delimiter, start)) != string::npos) {
            output.push_back(str.substr(start, end - start));
            start = end + 1;
        }
        output.push_back(str.substr(start));
        return output;
    }

    vector<string> fixPeers(const vector<PeerInfo> & inputPeers) {
        vector<string> fixedPeers;
        for (const auto & peer : inputPeers) {
            const auto parts = split(peer.address, "/");
            fixedPeers.push_back(parts[0] + ":" + parts.back());
        }
        return fixedPeers;
    }

    //TODO: make cleaner impl, maybe move to fileManager?
    std::vector<App::FileInfo> chunkifyFile(const std::string & filePath) {
        std::ifstream file(filePath, std::ios::in | std::ios::binary);
        if (!file) {
            return {};
        }
        file.seekg(0, std::ios::end);
        uint64_t size = file.tellg();
        file.close();

        std::vector<App::FileInfo> chunks;

        uint64_t c = 0;
        // push chunks with size App::fileChunkSize
        for (; size >= App::fileChunkSize; c += App::fileChunkSize) {
            chunks.push_back({ c, App::fileChunkSize, {} });
            size -= App::fileChunkSize;
        }

        // if there is more of the file, make it last chunk
        if (size > 0) {
            chunks.push_back({ c, size, {} });
        }

        return chunks;
    }
}

bool App::importFile(const std::string & filePath) {
    cout << "Imporintg file " << filePath << endl;

    if (storage.find(filePath) != storage.end()) {
        cout << "File already in storage" << endl;
        return false;
    }

    auto peers = fixPeers(networkManager->get_peers());

	if (!peers.size()) {
        cout << "No peers connected" << endl;
		return false;
	}

    std::vector<FileInfo> fileChunks = chunkifyFile(filePath);

	auto peerIter = peers.cbegin();

    // circular iterator over std::vector
    auto next = [](decltype(peerIter) & iter, decltype(peers) & container) {
        if (++iter == container.end()) {
            iter = container.begin();
        }
    };

    for (auto & chunk : fileChunks) {

        for (int c = 0; c < static_cast<int>(FileAvailability::High); ++c) {
            cout << "Sending chunk to " << *peerIter << endl;
            uint64_t sentChunkId = fileManager->send(*peerIter, filePath, chunk.start, chunk.start + chunk.size);

            if (sentChunkId == 0) {
                cout << "Failed to transfer chunk to host " << *peerIter << " chunk start " << chunk.start << endl;
                break;
            } else {
                cout << "Imorted chunk with ID " << sentChunkId << " to host " << *peerIter << endl;
                chunk.hosts.push_back(make_pair(*peerIter, sentChunkId));
            }
        }

        next(peerIter, peers);
    }

    storage[filePath] = fileChunks;
    return true;
}

App::FileAvailability App::isFileInStorage(const std::string & filePath) {
    auto file = storage.find(filePath);

    if (file == storage.end()) {
        cout << "File not in storage" << endl;
        return FileAvailability::None;
    }

    const auto & peers = networkManager->get_peers();

	if (!peers.size()){
        cout << "No peers connected" << endl;
		return FileAvailability::None;
	}

    FileAvailability fileStatus = FileAvailability::High;

    // Go trough all of the chunks and check which of them has least connected hosts
    for (auto & chunk : file->second) {
        int currentChunk = 0;
        for (auto & host : chunk.hosts) {

            cout << "Checking chunk with ID: " << host.second << " with host " << host.first << endl;

            currentChunk +=
                std::any_of(peers.begin(), peers.end(), [&host](const PeerInfo & info) {
                    const auto & parts = split(info.address, "/");
                    const auto & peerAddress = parts[0] + ":" + parts.back();

                    return peerAddress == host.first && info.connected;
                });
        }
        if (!currentChunk) {
            cout << "Chunk not found - " << chunk.start << endl;
        }
        fileStatus = static_cast<FileAvailability>(
            std::min<int>(currentChunk, static_cast<int>(fileStatus)));
    }

    return fileStatus;
}

bool App::exportFile(const std::string & storageFile, const std::string & outputFilePath) {
    auto file = storage.find(storageFile);
    if (file == storage.end()) {
        cout << "File not in storage" << endl;
        return false;
    }

    ofstream outputFile(outputFilePath, ios::trunc | ios::binary);
    if (!outputFile) {
        cout << "Failed to open export file " << outputFilePath << endl;
        return false;
    }

    for (const auto & chunk : file->second) {
        bool gotChunk = false;
        for (const auto & chunkLocation : chunk.hosts) {
            auto data = fileManager->getFile(chunkLocation.first, chunkLocation.second);
            if (data) {
                gotChunk = true;
                if (!outputFile.write(data.get(), chunk.size)) {
                    return false;
                }
                break; // all good chink written to file
            } else {
                cout << "Failed to receive chunk with ID: " << chunkLocation.second << " with host " << chunkLocation.first << endl;
            }

        }
        if (!gotChunk) {
            cout << "Chunk failed to export" << endl;
            return false;
        }
    }

    return true;
}
<|endoftext|>


<commit_before>
#include "sdOSCResponder.h"
#include <vector>
#include <sstream>

using namespace std;

sdOSCResponder::sdOSCResponder(sdScene *scene){
    sdOSCResponder::scene =scene;
}

void sdOSCResponder::forwardOSCMessage(string oscMessage){
    // interpret

    string addressPattern, typeTag, argument;
    vector <string>argumentVector;
    istringstream iss(oscMessage);
    iss >> addressPattern;
    iss >> typeTag; // type tag will be ignored

    if(typeTag[0] != ','){
        // typeTag ommited
        argumentVector.push_back(typeTag);
    }

    iss >> argument;
    while(argument){
        argumentVector.push_back(argument);
        iss >> argument;
    }

    // separate address Pattern to segments
    vector<string> addressVector;
    size_t pos = 0, offset = 1;
    while (pos != string::npos) {
        int len;
        pos  = addressPattern.find('/',offset);
        len = pos - offset;
        addressVector.push_back(addressPattern.substr(offset, len));
        offset = pos+1;
    }

    // if it's not a spatdif message
    if(addressVector[0] != "spatdif") return;

    // check type of message
    string type = addressVector[1];
    if(type == "source" || type == "sink"){

        string entityName = addressVector[2];
        sdEntity* entity = scene-> getEntity(entityName);
        if(!entity){
            EKind kind = type == "source" ? SD_SOURCE : SD_SINK;
            entity = scene.addEntity(entityName, kind);
        }

        string descriptor = addressVector[3];

    }else if(type == "time"){
        istringstream is;
        is.str(argumentVector[0]);
        is >> time;
    }else if(type == "meta"){

    }

}<commit_msg>bug fix in sdOSCResponder.cpp<commit_after>
#include "sdOSCResponder.h"
#include <vector>
#include <sstream>

using namespace std;

sdOSCResponder::sdOSCResponder(sdScene *scene){
    sdOSCResponder::scene =scene;
}

void sdOSCResponder::forwardOSCMessage(string oscMessage){
    // interpret

    string addressPattern, typeTag, argument;
    vector <string>argumentVector;
    istringstream iss(oscMessage);
    iss >> addressPattern;
    iss >> typeTag; // type tag will be ignored

    if(typeTag[0] != ','){
        // typeTag ommited
        argumentVector.push_back(typeTag);
    }

    iss >> argument;
    while(argument != " "){
        argumentVector.push_back(argument);
        iss >> argument;
    }

    // separate address Pattern to segments
    vector<string> addressVector;
    size_t pos = 0, offset = 1;
    while (pos != string::npos) {
        int len;
        pos  = addressPattern.find('/',offset);
        len = pos - offset;
        addressVector.push_back(addressPattern.substr(offset, len));
        offset = pos+1;
    }

    // if it's not a spatdif message
    if(addressVector[0] != "spatdif") return;

    // check type of message
    string type = addressVector[1];
    if(type == "source" || type == "sink"){

        string entityName = addressVector[2];
        sdEntity* entity = scene-> getEntity(entityName);
        if(!entity){
            EKind kind = type == "source" ? SD_SOURCE : SD_SINK;
            entity = scene->addEntity(entityName, kind);
        }

        string descriptor = addressVector[3];

    }else if(type == "time"){
        istringstream is;
        is.str(argumentVector[0]);
        is >> time;
    }else if(type == "meta"){

    }

}<|endoftext|>