<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <fstream>

// Local includes
#include "mesh_data.h"
#include "mesh_base.h"
#include "xdr_cxx.h"
#include "elem.h"

namespace libMesh
{

//------------------------------------------------------
// MeshData functions
void MeshData::read_xdr (const std::string& name,
			 const XdrMODE mode)
{
  /**
   * This code implements the output of the MeshData
   * object in XDR format.  This warrants some documentation.
   * The output consists of 8 sections:
   *
   *   1.) The name of the data stored, if provided (string)
   *
   *   2.) A switch whether real or complex data is stored (string)
   *
   *   3.) The number of nodes for which values are stored
   *       (unsigned int)
   *
   *   4.) The number of elements for which values are stored
   *       (unsigned int)
   *
   *   for each node
   *
   *     5.) The foreign node id (unsigned int)
   *
   *     6.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   *   for each element
   *
   *     7.) The foreign element id (unsigned int)
   *
   *     8.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   * Note that the actual IO is handled through the Xdr class
   * (to be renamed later?) which provides a uniform interface to
   * both the XDR (eXternal Data Representation) interface and standard
   * ASCII output.  Thus this one section of code will write XDR or ASCII
   * files with no changes.
   */

  // we should better be active or in compatibility mode
  libmesh_assert (_active || _compatibility_mode);

  // make sure the id maps are ready
  libmesh_assert (_node_id_map_closed);
  libmesh_assert (_elem_id_map_closed);

  /**
   * clear the data, but keep the id maps
   */
  this->clear();

  Xdr io(name, mode);

  /*
   * all processors read the data in the same format,
   * but only the processor that owns the element stores
   * element-associated data.  For nodes, i haven't come
   * up with such asmart idea, yet... :-P
   */
  const unsigned int proc_id = _mesh.processor_id();

  /**
   * 1.)
   *
   * Read the descriptive name
   */
  {
    std::string desc = "";
    io.data (desc);
    this->_data_descriptor = desc;
  }

  /**
   * 2.)
   *
   * Read: either real or complex
   */
  {
    std::string vtype="";
    io.data (vtype);
#ifdef LIBMESH_USE_COMPLEX_NUMBERS
    if (vtype != "COMPLEX")
      {
	libMesh::err << "ERROR: File does not contain complex-valued data!"
		      << std::endl;
	libmesh_error();
      }
#elif LIBMESH_USE_REAL_NUMBERS
    if (vtype != "REAL")
      {
	libMesh::err << "ERROR: File does not contain real-valued data!"
		      << std::endl;
	libmesh_error();
      }
#else
    /*
     * What number type is this?
     */
    libmesh_error();
#endif
  }

  /**
   * 3.)
   *
   * Read the number of nodes for which data is there
   */
  unsigned int n_node = 0;
  io.data (n_node);

  /**
   * 4.)
   *
   * Read the number of elements for which data is there
   */
  unsigned int n_elem = 0;
  io.data (n_elem);

  unsigned int previous_values_size = 0;

  for (unsigned int n_cnt=0; n_cnt < n_node; n_cnt++)
    {
      /**
       * 5.)
       *
       * Read the foreign node id, locate the
       * Node* associated with this foreign id
       */
      unsigned int f_id = 0;
      io.data (f_id);

      const Node* node = foreign_id_to_node(f_id);

      /**
       * 6.)
       *
       * the actual values for this node, Xdr knows
       * the length
       */
      {
        std::vector<Number> values;
	io.data (values);

#ifdef DEBUG
	/*
	 * make sure the size of the values vectors
	 * are identical for all nodes
	 */
	if (n_cnt == 0)
	    previous_values_size = values.size();
	else
	  {
	    if (previous_values_size != values.size())
	      {
		libMesh::err << "ERROR: Size mismatch for n_cnt = " << n_cnt << std::endl;
		libmesh_error();
	      }
	  }
#endif

	/**
	 * insert this node and the values in the _node_data
	 */
	_node_data.insert (std::make_pair(node, values));
      }
    }

  previous_values_size = 0;

  for (unsigned int n_cnt=0; n_cnt < n_elem; n_cnt++)
    {
      /**
       * 7.)
       *
       * Read the foreign elem id, locate the Elem*
       */
      unsigned int f_id = 0;
      io.data (f_id);

      const Elem* elem = foreign_id_to_elem(f_id);

      /**
       * 8.)
       *
       * the actual values for this elem, Xdr knows
       * how many
       */
      {
        std::vector<Number> values;
	io.data (values);

#ifdef DEBUG
	/*
	 * make sure the size of the values vectors
	 * are identical for all elements
	 */
	if (n_cnt == 0)
	    previous_values_size = values.size();
	else
	  {
	    if (previous_values_size != values.size())
	      {
		libMesh::err << "ERROR: Size mismatch for n_cnt = " << n_cnt << std::endl;
		libmesh_error();
	      }
	  }
#endif

	/**
	 * insert this elem and the values in our _elem_data
	 * @e only when we own this element!
	 */
	if (elem->processor_id() == proc_id)
	  _elem_data.insert (std::make_pair(elem, values));
      }
    }

  /*
   * finished reading.  Now ready for use, provided
   * there was any data contained in the file.
   */
  libmesh_assert ((this->_node_data.size() != 0) || (this->_elem_data.size() != 0));

  this->_node_data_closed = true;
  this->_elem_data_closed = true;
}

void MeshData::write_xdr (const std::string& name,
			  const XdrMODE mode)
{
  /**
   * This code implements the output of the MeshData
   * object in XDR format.  This warrants some documentation.
   * The output consists of 8 sections:
   *
   *   1.) The name of the data stored, if provided (string)
   *
   *   2.) A switch whether real or complex data is stored (string)
   *
   *   3.) The number of nodes for which values are stored
   *       (unsigned int)
   *
   *   4.) The number of elements for which values are stored
   *       (unsigned int)
   *
   *   for each node
   *
   *     5.) The foreign node id (unsigned int)
   *
   *     6.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   *   for each element
   *
   *     7.) The foreign element id (unsigned int)
   *
   *     8.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   * Note that the actual IO is handled through the Xdr class
   * (to be renamed later?) which provides a uniform interface to
   * both the XDR (eXternal Data Representation) interface and standard
   * ASCII output.  Thus this one section of code will write XDR or ASCII
   * files with no changes.
   */

  /*
   * make sure the id maps are ready
   * and that we have data to write
   */
  libmesh_assert (_node_id_map_closed);
  libmesh_assert (_elem_id_map_closed);

  libmesh_assert (_node_data_closed);
  libmesh_assert (_elem_data_closed);

  Xdr io(name, mode);

  // all processors write the data in the same format
  //const unsigned int proc_id = _mesh.processor_id();

  /**
   * 1.)
   *
   * Write the descriptive name
   */
  {
    std::string desc = this->_data_descriptor;
    io.data (desc, "# Data description");
  }

  /**
   * 2.)
   *
   * Write: either real or complex
   */
  {
#ifdef LIBMESH_USE_COMPLEX_NUMBERS
    std::string desc = "COMPLEX";
#elif LIBMESH_USE_REAL_NUMBERS
    std::string desc = "REAL";
#else
better_you_choke_this...
#endif
    io.data (desc, "# type of values");
  }

  /**
   * 3.)
   *
   * Write the number of nodes for which data is there
   */
  {
    unsigned int n_node = this->_node_data.size();
    io.data (n_node, "# No. of nodes for which data is stored");
  }

  /**
   * 4.)
   *
   * Write the number of elements for which data is there
   */
  {
    unsigned int n_elem = this->_elem_data.size();
    io.data (n_elem, "# No. of elements for which data is stored");
  }

  std::map<const Node*,
           std::vector<Number> >::const_iterator nit = _node_data.begin ();

  for (; nit != _node_data.end(); ++nit)
    {
      const Node* node = (*nit).first;

      /**
       * 5.)
       *
       * Write the foreign node id
       */
      {
	unsigned int f_id = node_to_foreign_id (node);
	io.data (f_id, "# Foreign node id");
      }

      /**
       * 6.)
       *
       * the actual values for this node
       */
      {
	/*
	 * since we are iterating over our @e own
	 * map, this libmesh_assert should never break...
	 */
	libmesh_assert (this->has_data(node));

	const std::vector<Number>& values = this->get_data(node);

	/*
	 * copy the data to a local buf, since
	 * the Xdr class needs write access, even
	 * when only reading data
	 */
	std::vector<Number> buf = values;
	io.data (buf, "# Values");
      }
    }

  std::map<const Elem*,
           std::vector<Number> >::const_iterator eit = _elem_data.begin ();

  for (; eit != _elem_data.end(); ++eit)
    {
      const Elem* elem = (*eit).first;

      /**
       * 7.)
       *
       * Write the foreign element id
       */
      {
	unsigned int f_id = elem_to_foreign_id (elem);
	io.data (f_id, "# Foreign element id");
      }

      /**
       * 8.)
       *
       * the actual values for this element
       */
      {
	/*
	 * since we are iterating over our @e own
	 * map, this libmesh_assert should never break...
	 */
	libmesh_assert (this->has_data(elem));

	const std::vector<Number>& values = this->get_data(elem);

	/*
	 * copy the data to a local buf, since
	 * the Xdr class needs write access, even
	 * when only reading data
	 */
	std::vector<Number> buf = values;
	io.data (buf, "# Values");
      }
    }
}

} // namespace libMesh

<commit_msg>Avoid "unused variables" warnings in non-debug modes<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2012 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// C++ includes
#include <fstream>

// Local includes
#include "mesh_data.h"
#include "mesh_base.h"
#include "xdr_cxx.h"
#include "elem.h"

namespace libMesh
{

//------------------------------------------------------
// MeshData functions
void MeshData::read_xdr (const std::string& name,
			 const XdrMODE mode)
{
  /**
   * This code implements the output of the MeshData
   * object in XDR format.  This warrants some documentation.
   * The output consists of 8 sections:
   *
   *   1.) The name of the data stored, if provided (string)
   *
   *   2.) A switch whether real or complex data is stored (string)
   *
   *   3.) The number of nodes for which values are stored
   *       (unsigned int)
   *
   *   4.) The number of elements for which values are stored
   *       (unsigned int)
   *
   *   for each node
   *
   *     5.) The foreign node id (unsigned int)
   *
   *     6.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   *   for each element
   *
   *     7.) The foreign element id (unsigned int)
   *
   *     8.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   * Note that the actual IO is handled through the Xdr class
   * (to be renamed later?) which provides a uniform interface to
   * both the XDR (eXternal Data Representation) interface and standard
   * ASCII output.  Thus this one section of code will write XDR or ASCII
   * files with no changes.
   */

  // we should better be active or in compatibility mode
  libmesh_assert (_active || _compatibility_mode);

  // make sure the id maps are ready
  libmesh_assert (_node_id_map_closed);
  libmesh_assert (_elem_id_map_closed);

  /**
   * clear the data, but keep the id maps
   */
  this->clear();

  Xdr io(name, mode);

  /*
   * all processors read the data in the same format,
   * but only the processor that owns the element stores
   * element-associated data.  For nodes, i haven't come
   * up with such asmart idea, yet... :-P
   */
  const unsigned int proc_id = _mesh.processor_id();

  /**
   * 1.)
   *
   * Read the descriptive name
   */
  {
    std::string desc = "";
    io.data (desc);
    this->_data_descriptor = desc;
  }

  /**
   * 2.)
   *
   * Read: either real or complex
   */
  {
    std::string vtype="";
    io.data (vtype);
#ifdef LIBMESH_USE_COMPLEX_NUMBERS
    if (vtype != "COMPLEX")
      {
	libMesh::err << "ERROR: File does not contain complex-valued data!"
		      << std::endl;
	libmesh_error();
      }
#elif LIBMESH_USE_REAL_NUMBERS
    if (vtype != "REAL")
      {
	libMesh::err << "ERROR: File does not contain real-valued data!"
		      << std::endl;
	libmesh_error();
      }
#else
    /*
     * What number type is this?
     */
    libmesh_error();
#endif
  }

  /**
   * 3.)
   *
   * Read the number of nodes for which data is there
   */
  unsigned int n_node = 0;
  io.data (n_node);

  /**
   * 4.)
   *
   * Read the number of elements for which data is there
   */
  unsigned int n_elem = 0;
  io.data (n_elem);

#ifdef DEBUG
  unsigned int previous_values_size = 0;
#endif

  for (unsigned int n_cnt=0; n_cnt < n_node; n_cnt++)
    {
      /**
       * 5.)
       *
       * Read the foreign node id, locate the
       * Node* associated with this foreign id
       */
      unsigned int f_id = 0;
      io.data (f_id);

      const Node* node = foreign_id_to_node(f_id);

      /**
       * 6.)
       *
       * the actual values for this node, Xdr knows
       * the length
       */
      {
        std::vector<Number> values;
	io.data (values);

#ifdef DEBUG
	/*
	 * make sure the size of the values vectors
	 * are identical for all nodes
	 */
	if (n_cnt == 0)
	    previous_values_size = values.size();
	else
	  {
	    if (previous_values_size != values.size())
	      {
		libMesh::err << "ERROR: Size mismatch for n_cnt = " << n_cnt << std::endl;
		libmesh_error();
	      }
	  }
#endif

	/**
	 * insert this node and the values in the _node_data
	 */
	_node_data.insert (std::make_pair(node, values));
      }
    }

#ifdef DEBUG
  previous_values_size = 0;
#endif

  for (unsigned int n_cnt=0; n_cnt < n_elem; n_cnt++)
    {
      /**
       * 7.)
       *
       * Read the foreign elem id, locate the Elem*
       */
      unsigned int f_id = 0;
      io.data (f_id);

      const Elem* elem = foreign_id_to_elem(f_id);

      /**
       * 8.)
       *
       * the actual values for this elem, Xdr knows
       * how many
       */
      {
        std::vector<Number> values;
	io.data (values);

#ifdef DEBUG
	/*
	 * make sure the size of the values vectors
	 * are identical for all elements
	 */
	if (n_cnt == 0)
	    previous_values_size = values.size();
	else
	  {
	    if (previous_values_size != values.size())
	      {
		libMesh::err << "ERROR: Size mismatch for n_cnt = " << n_cnt << std::endl;
		libmesh_error();
	      }
	  }
#endif

	/**
	 * insert this elem and the values in our _elem_data
	 * @e only when we own this element!
	 */
	if (elem->processor_id() == proc_id)
	  _elem_data.insert (std::make_pair(elem, values));
      }
    }

  /*
   * finished reading.  Now ready for use, provided
   * there was any data contained in the file.
   */
  libmesh_assert ((this->_node_data.size() != 0) || (this->_elem_data.size() != 0));

  this->_node_data_closed = true;
  this->_elem_data_closed = true;
}

void MeshData::write_xdr (const std::string& name,
			  const XdrMODE mode)
{
  /**
   * This code implements the output of the MeshData
   * object in XDR format.  This warrants some documentation.
   * The output consists of 8 sections:
   *
   *   1.) The name of the data stored, if provided (string)
   *
   *   2.) A switch whether real or complex data is stored (string)
   *
   *   3.) The number of nodes for which values are stored
   *       (unsigned int)
   *
   *   4.) The number of elements for which values are stored
   *       (unsigned int)
   *
   *   for each node
   *
   *     5.) The foreign node id (unsigned int)
   *
   *     6.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   *   for each element
   *
   *     7.) The foreign element id (unsigned int)
   *
   *     8.) The actual values (vector of real/complex)
   *
   *   end node loop
   *
   * Note that the actual IO is handled through the Xdr class
   * (to be renamed later?) which provides a uniform interface to
   * both the XDR (eXternal Data Representation) interface and standard
   * ASCII output.  Thus this one section of code will write XDR or ASCII
   * files with no changes.
   */

  /*
   * make sure the id maps are ready
   * and that we have data to write
   */
  libmesh_assert (_node_id_map_closed);
  libmesh_assert (_elem_id_map_closed);

  libmesh_assert (_node_data_closed);
  libmesh_assert (_elem_data_closed);

  Xdr io(name, mode);

  // all processors write the data in the same format
  //const unsigned int proc_id = _mesh.processor_id();

  /**
   * 1.)
   *
   * Write the descriptive name
   */
  {
    std::string desc = this->_data_descriptor;
    io.data (desc, "# Data description");
  }

  /**
   * 2.)
   *
   * Write: either real or complex
   */
  {
#ifdef LIBMESH_USE_COMPLEX_NUMBERS
    std::string desc = "COMPLEX";
#elif LIBMESH_USE_REAL_NUMBERS
    std::string desc = "REAL";
#else
better_you_choke_this...
#endif
    io.data (desc, "# type of values");
  }

  /**
   * 3.)
   *
   * Write the number of nodes for which data is there
   */
  {
    unsigned int n_node = this->_node_data.size();
    io.data (n_node, "# No. of nodes for which data is stored");
  }

  /**
   * 4.)
   *
   * Write the number of elements for which data is there
   */
  {
    unsigned int n_elem = this->_elem_data.size();
    io.data (n_elem, "# No. of elements for which data is stored");
  }

  std::map<const Node*,
           std::vector<Number> >::const_iterator nit = _node_data.begin ();

  for (; nit != _node_data.end(); ++nit)
    {
      const Node* node = (*nit).first;

      /**
       * 5.)
       *
       * Write the foreign node id
       */
      {
	unsigned int f_id = node_to_foreign_id (node);
	io.data (f_id, "# Foreign node id");
      }

      /**
       * 6.)
       *
       * the actual values for this node
       */
      {
	/*
	 * since we are iterating over our @e own
	 * map, this libmesh_assert should never break...
	 */
	libmesh_assert (this->has_data(node));

	const std::vector<Number>& values = this->get_data(node);

	/*
	 * copy the data to a local buf, since
	 * the Xdr class needs write access, even
	 * when only reading data
	 */
	std::vector<Number> buf = values;
	io.data (buf, "# Values");
      }
    }

  std::map<const Elem*,
           std::vector<Number> >::const_iterator eit = _elem_data.begin ();

  for (; eit != _elem_data.end(); ++eit)
    {
      const Elem* elem = (*eit).first;

      /**
       * 7.)
       *
       * Write the foreign element id
       */
      {
	unsigned int f_id = elem_to_foreign_id (elem);
	io.data (f_id, "# Foreign element id");
      }

      /**
       * 8.)
       *
       * the actual values for this element
       */
      {
	/*
	 * since we are iterating over our @e own
	 * map, this libmesh_assert should never break...
	 */
	libmesh_assert (this->has_data(elem));

	const std::vector<Number>& values = this->get_data(elem);

	/*
	 * copy the data to a local buf, since
	 * the Xdr class needs write access, even
	 * when only reading data
	 */
	std::vector<Number> buf = values;
	io.data (buf, "# Values");
      }
    }
}

} // namespace libMesh

<|endoftext|>


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

#include "base/command_line.h"
#include "chrome/browser/media/webrtc_browsertest_base.h"
#include "chrome/browser/media/webrtc_browsertest_common.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"

static const char kMainWebrtcTestHtmlPage[] =
    "/webrtc/webrtc_jsep01_test.html";

// These tests runs on real webcams and ensure WebRTC can acquire webcams
// correctly. They will do nothing if there are no webcams on the system.
// The webcam on the system must support up to 1080p, or the test will fail.
class WebRtcWebcamBrowserTest : public WebRtcTestBase {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    EXPECT_FALSE(command_line->HasSwitch(
        switches::kUseFakeDeviceForMediaStream));
    EXPECT_FALSE(command_line->HasSwitch(
        switches::kUseFakeUIForMediaStream));
  }

  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    DetectErrorsInJavaScript();  // Look for errors in our rather complex js.
  }
};

IN_PROC_BROWSER_TEST_F(WebRtcWebcamBrowserTest,
                       TestAcquiringAndReacquiringWebcam) {
  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
  GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
  ui_test_utils::NavigateToURL(browser(), url);
  content::WebContents* tab =
      browser()->tab_strip_model()->GetActiveWebContents();

  if (!HasWebcamAvailableOnSystem(tab)) {
    LOG(INFO) << "No webcam found on bot: skipping...";
    return;
  }

  GetUserMediaWithSpecificConstraintsAndAccept(tab,
                                               kAudioVideoCallConstraintsVGA);
  StartDetectingVideo(tab, "local-view");
  WaitForVideoToPlay(tab);
  EXPECT_EQ("640x480", GetStreamSize(tab, "local-view"));
  CloseLastLocalStream(tab);
  GetUserMediaWithSpecificConstraintsAndAccept(tab,
                                               kAudioVideoCallConstraintsQVGA);
  StartDetectingVideo(tab, "local-view");
  WaitForVideoToPlay(tab);
  EXPECT_EQ("320x240", GetStreamSize(tab, "local-view"));
  CloseLastLocalStream(tab);
  GetUserMediaWithSpecificConstraintsAndAccept(tab,
                                               kAudioVideoCallConstraints360p);
  StartDetectingVideo(tab, "local-view");
  WaitForVideoToPlay(tab);
  EXPECT_EQ("640x360", GetStreamSize(tab, "local-view"));
  CloseLastLocalStream(tab);

  // Broken on all platforms for C920 webcams: see http://crbug.com/360512.
//  GetUserMediaWithSpecificConstraintsAndAccept(tab,
//                                              kAudioVideoCallConstraints720p);
//  StartDetectingVideo(tab, "local-view");
//  WaitForVideoToPlay(tab);
//  EXPECT_EQ("1280x720", GetStreamSize(tab, "local-view"));
//  CloseLastLocalStream(tab);
//  GetUserMediaWithSpecificConstraintsAndAccept(tab,
//                                             kAudioVideoCallConstraints1080p);
//  StartDetectingVideo(tab, "local-view");
//  WaitForVideoToPlay(tab);
//  EXPECT_EQ("1920x1080", GetStreamSize(tab, "local-view"));
//  CloseLastLocalStream(tab);
}
<commit_msg>Re-enabling WebRTC HD cam tests after Logitech C920 fix.<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/media/webrtc_browsertest_base.h"
#include "chrome/browser/media/webrtc_browsertest_common.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"

static const char kMainWebrtcTestHtmlPage[] =
    "/webrtc/webrtc_jsep01_test.html";

// These tests runs on real webcams and ensure WebRTC can acquire webcams
// correctly. They will do nothing if there are no webcams on the system.
// The webcam on the system must support up to 1080p, or the test will fail.
class WebRtcWebcamBrowserTest : public WebRtcTestBase {
 public:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    EXPECT_FALSE(command_line->HasSwitch(
        switches::kUseFakeDeviceForMediaStream));
    EXPECT_FALSE(command_line->HasSwitch(
        switches::kUseFakeUIForMediaStream));
  }

  virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
    DetectErrorsInJavaScript();  // Look for errors in our rather complex js.
  }

 protected:
  std::string GetUserMediaAndGetStreamSize(content::WebContents* tab,
                                           const std::string& constraints) {
    GetUserMediaWithSpecificConstraintsAndAccept(tab, constraints);
    StartDetectingVideo(tab, "local-view");
    WaitForVideoToPlay(tab);
    std::string actual_stream_size = GetStreamSize(tab, "local-view");
    CloseLastLocalStream(tab);
    return actual_stream_size;
  }
};

IN_PROC_BROWSER_TEST_F(WebRtcWebcamBrowserTest,
                       TestAcquiringAndReacquiringWebcam) {
  ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
  GURL url(embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage));
  ui_test_utils::NavigateToURL(browser(), url);
  content::WebContents* tab =
      browser()->tab_strip_model()->GetActiveWebContents();

  if (!HasWebcamAvailableOnSystem(tab)) {
    LOG(INFO) << "No webcam found on bot: skipping...";
    return;
  }

  EXPECT_EQ("640x480",
            GetUserMediaAndGetStreamSize(tab, kAudioVideoCallConstraintsVGA));
  EXPECT_EQ("320x240",
            GetUserMediaAndGetStreamSize(tab, kAudioVideoCallConstraintsQVGA));
  EXPECT_EQ("640x360",
            GetUserMediaAndGetStreamSize(tab, kAudioVideoCallConstraints360p));
  EXPECT_EQ("1280x720",
            GetUserMediaAndGetStreamSize(tab, kAudioVideoCallConstraints720p));
  EXPECT_EQ("1920x1080",
            GetUserMediaAndGetStreamSize(tab, kAudioVideoCallConstraints1080p));
}
<|endoftext|>


<commit_before>#include "ovpCBoxAlgorithmSoundPlayer.h"

#if defined OVP_OS_Windows
 #include <windows.h>
 #include <mmsystem.h>
#endif
#if defined OVP_OS_Linux
 #include <unistd.h>
#endif

#include <string>
#include <cstdlib>

using namespace OpenViBE;
using namespace OpenViBE::Kernel;
using namespace OpenViBE::Plugins;

using namespace OpenViBEPlugins;
using namespace OpenViBEPlugins::Stimulation;

using namespace std;

boolean CBoxAlgorithmSoundPlayer::initialize(void)
{
	IBox& l_rStaticBoxContext=this->getStaticBoxContext();

	m_pStreamDecoder=&getAlgorithmManager().getAlgorithm(getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationStreamDecoder));
	m_pStreamDecoder->initialize();

	for(uint32 i=0; i<l_rStaticBoxContext.getSettingCount(); i+=2)
	{
		uint64 l_ui64StimulationIdentifier=FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i);
		CString l_sSoundFilename=FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i+1);

		m_vSoundInfo[l_ui64StimulationIdentifier].push_back(l_sSoundFilename);
	}
	return true;
}

boolean CBoxAlgorithmSoundPlayer::uninitialize(void)
{
	m_pStreamDecoder->uninitialize();
	getAlgorithmManager().releaseAlgorithm(*m_pStreamDecoder);

	return true;
}

boolean CBoxAlgorithmSoundPlayer::processInput(uint32 ui32InputIndex)
{
	getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();

	return true;
}

boolean CBoxAlgorithmSoundPlayer::process(void)
{
	IBoxIO& l_rDynamicBoxContext=this->getDynamicBoxContext();

	std::map < uint64, std::vector < CString > >::const_iterator it;
	std::vector < CString >::const_iterator it2;
	for(uint32 i=0; i<l_rDynamicBoxContext.getInputChunkCount(0); i++)
	{
		TParameterHandler < const IMemoryBuffer* > l_ipMemoryBuffer(m_pStreamDecoder->getInputParameter(OVP_GD_Algorithm_StimulationStreamDecoder_InputParameterId_MemoryBufferToDecode));
		l_ipMemoryBuffer=l_rDynamicBoxContext.getInputChunk(0, i);
		m_pStreamDecoder->process();
		if(m_pStreamDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationStreamDecoder_OutputTriggerId_ReceivedHeader))
		{
		}
		if(m_pStreamDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationStreamDecoder_OutputTriggerId_ReceivedBuffer))
		{
			TParameterHandler < IStimulationSet* > l_opStimulationSet(m_pStreamDecoder->getOutputParameter(OVP_GD_Algorithm_StimulationStreamDecoder_OutputParameterId_StimulationSet));
			for(uint32 j=0; j<l_opStimulationSet->getStimulationCount(); j++)
			{
				it=m_vSoundInfo.find(l_opStimulationSet->getStimulationIdentifier(j));
				if(it!=m_vSoundInfo.end())
				{
					for(it2=it->second.begin(); it2!=it->second.end(); it2++)
					{
#if defined OVP_OS_Windows
						::sndPlaySound(it2->toASCIIString(), SND_NOSTOP | SND_ASYNC );
#elif defined OVP_OS_Linux
						string l_sCommand;
						l_sCommand+="cat ";
						l_sCommand+=it2->toASCIIString();
						l_sCommand+=" > /dev/dsp &";
						int l_iResult=::system(l_sCommand.c_str());
#else
						getBoxAlgorithmContext()->getPlayerContext()->getLogManager() << LogLevel_Warning << "Sound player not yet implemented for this OS\n";
#endif
					}
				}
			}
		}
		if(m_pStreamDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationStreamDecoder_OutputTriggerId_ReceivedEnd))
		{
		}

		l_rDynamicBoxContext.markInputAsDeprecated(0, i);
	}

	return true;
}
<commit_msg><commit_after>#include "ovpCBoxAlgorithmSoundPlayer.h"

#if defined OVP_OS_Windows
 #include <windows.h>
 #include <mmsystem.h>
#endif
#if defined OVP_OS_Linux
 #include <unistd.h>
#endif

#include <string>
#include <cstdlib>

using namespace OpenViBE;
using namespace OpenViBE::Kernel;
using namespace OpenViBE::Plugins;

using namespace OpenViBEPlugins;
using namespace OpenViBEPlugins::Stimulation;

using namespace std;

#define boolean OpenViBE::boolean

boolean CBoxAlgorithmSoundPlayer::initialize(void)
{
	IBox& l_rStaticBoxContext=this->getStaticBoxContext();

	m_pStreamDecoder=&getAlgorithmManager().getAlgorithm(getAlgorithmManager().createAlgorithm(OVP_GD_ClassId_Algorithm_StimulationStreamDecoder));
	m_pStreamDecoder->initialize();

	for(uint32 i=0; i<l_rStaticBoxContext.getSettingCount(); i+=2)
	{
		uint64 l_ui64StimulationIdentifier=FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i);
		CString l_sSoundFilename=FSettingValueAutoCast(*this->getBoxAlgorithmContext(), i+1);

		m_vSoundInfo[l_ui64StimulationIdentifier].push_back(l_sSoundFilename);
	}
	return true;
}

boolean CBoxAlgorithmSoundPlayer::uninitialize(void)
{
	m_pStreamDecoder->uninitialize();
	getAlgorithmManager().releaseAlgorithm(*m_pStreamDecoder);

	return true;
}

boolean CBoxAlgorithmSoundPlayer::processInput(uint32 ui32InputIndex)
{
	getBoxAlgorithmContext()->markAlgorithmAsReadyToProcess();

	return true;
}

boolean CBoxAlgorithmSoundPlayer::process(void)
{
	IBoxIO& l_rDynamicBoxContext=this->getDynamicBoxContext();

	std::map < uint64, std::vector < CString > >::const_iterator it;
	std::vector < CString >::const_iterator it2;
	for(uint32 i=0; i<l_rDynamicBoxContext.getInputChunkCount(0); i++)
	{
		TParameterHandler < const IMemoryBuffer* > l_ipMemoryBuffer(m_pStreamDecoder->getInputParameter(OVP_GD_Algorithm_StimulationStreamDecoder_InputParameterId_MemoryBufferToDecode));
		l_ipMemoryBuffer=l_rDynamicBoxContext.getInputChunk(0, i);
		m_pStreamDecoder->process();
		if(m_pStreamDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationStreamDecoder_OutputTriggerId_ReceivedHeader))
		{
		}
		if(m_pStreamDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationStreamDecoder_OutputTriggerId_ReceivedBuffer))
		{
			TParameterHandler < IStimulationSet* > l_opStimulationSet(m_pStreamDecoder->getOutputParameter(OVP_GD_Algorithm_StimulationStreamDecoder_OutputParameterId_StimulationSet));
			for(uint32 j=0; j<l_opStimulationSet->getStimulationCount(); j++)
			{
				it=m_vSoundInfo.find(l_opStimulationSet->getStimulationIdentifier(j));
				if(it!=m_vSoundInfo.end())
				{
					for(it2=it->second.begin(); it2!=it->second.end(); it2++)
					{
#if defined OVP_OS_Windows
						::sndPlaySound(it2->toASCIIString(), SND_NOSTOP | SND_ASYNC );
#elif defined OVP_OS_Linux
						string l_sCommand;
						l_sCommand+="cat ";
						l_sCommand+=it2->toASCIIString();
						l_sCommand+=" > /dev/dsp &";
						int l_iResult=::system(l_sCommand.c_str());
#else
						getBoxAlgorithmContext()->getPlayerContext()->getLogManager() << LogLevel_Warning << "Sound player not yet implemented for this OS\n";
#endif
					}
				}
			}
		}
		if(m_pStreamDecoder->isOutputTriggerActive(OVP_GD_Algorithm_StimulationStreamDecoder_OutputTriggerId_ReceivedEnd))
		{
		}

		l_rDynamicBoxContext.markInputAsDeprecated(0, i);
	}

	return true;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Abhishek Agrawal (abhishek.agrawal@protonmail.com)
 * Distributed under the MIT License.
 * See accompanying file LICENSE.md or copy at http://opensource.org/licenses/MIT
 */

// This code will convert multiple cartesian state vectors
// into TLE and check where exactly the Atom is failing. The cartesian
// vectors are generated by converting randomly generated keplerian elements.
// The conversion is achieved through the pykep library of ESA.

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <fstream>

#include <gsl/gsl_multiroots.h>
#include <gsl/gsl_vector.h>

#include <libsgp4/DateTime.h>
#include <libsgp4/Eci.h>
#include <libsgp4/Globals.h>
#include <libsgp4/SGP4.h>
#include <libsgp4/Tle.h>

#include <Astro/astro.hpp>
#include <SML/sml.hpp>

#include <Atom/printFunctions.hpp>

#include <Astro/orbitalElementConversions.hpp>
#include <Atom/convertCartesianStateToTwoLineElements.hpp>

#include "CppProject/randomKepElem.hpp"

typedef double Real;
typedef std::vector< Real > Vector6;
typedef std::vector< Real > Vector3;
typedef std::vector< Real > Vector2;
typedef std::vector < std::vector < Real > > Vector2D;

int main(void)
{
    // some constants
    // earth radius
    // grav. parameter 'mu' of earth
    // value of Pi

	// initialize input parameters for the function generating random orbital elements. Description can be
    // found in randomKepElem.hpp for each of the following parameters.
    const Vector2 range_a      = { 0, 1 };
    const Vector2 range_e      = { 0, 1 };
    const Vector2 range_i      = { 0, 1 };
    const Vector2 range_raan   = { 0, 1 };
    const Vector2 range_w      = { 0, 1 };
    const Vector2 range_E      = { 0, 1 };
    const int limit            = 100;
    Vector2D randKepElem( limit, std::vector< Real >( 6 ) );

    // call the function to generate random keplerian orbital elements. Values are stored in randKepElem in a 2D
    // vector format. A single row represents one set of orbital elements, arranged in the same order as the
    // input argument order of the elements.
    randomKepElem::randomKepElem( range_a, range_e, range_i, range_raan, range_w, range_E, limit, randKepElem );

    // test output to check if the random numbers are generated without any errors
    std::cout << randKepElem[ 0 ][ 1 ] << std::endl;

    //store randomly generated keplerian element sets into a CSV file for easy viewing and use in future debugging of ATOM
    std::ofstream RandomKepElemFile;
    RandomKepElemFile.open("RandomKepElemFile.csv"); //file will be overwritten each time the code is run unless the name is changed here and the code recompiled

    for(int i = 0; i < limit; i++)
    {
        for(int j = 0; j < 6; j++)
        {
            RandomKepElemFile << randKepElem[ i ][ j ] << ",";
        }
        RandomKepElemFile << std::endl;
    }
    RandomKepElemFile.close();

    // generate sets of cartesian elements corresponding to each of the psuedo random orbital element set.
    // The conversion from keplerian elements to the cartesian elements is done using the PyKep library from ESA.

	// Tle convertedTle = atom::convertCartesianStateToTwoLineElements< Real, Vector6 >( cartesianState, DateTime( ) );

	// std::cout << convertedTle << std::endl;

    return EXIT_SUCCESS;
}

<commit_msg>added column headings in the CSV file which stores the randomly generated keplerian elements<commit_after>/*
 * Copyright (c) 2016 Abhishek Agrawal (abhishek.agrawal@protonmail.com)
 * Distributed under the MIT License.
 * See accompanying file LICENSE.md or copy at http://opensource.org/licenses/MIT
 */

// This code will convert multiple cartesian state vectors
// into TLE and check where exactly the Atom is failing. The cartesian
// vectors are generated by converting randomly generated keplerian elements.
// The conversion is achieved through the pykep library of ESA.

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include <fstream>

#include <gsl/gsl_multiroots.h>
#include <gsl/gsl_vector.h>

#include <libsgp4/DateTime.h>
#include <libsgp4/Eci.h>
#include <libsgp4/Globals.h>
#include <libsgp4/SGP4.h>
#include <libsgp4/Tle.h>

#include <Astro/astro.hpp>
#include <SML/sml.hpp>

#include <Atom/printFunctions.hpp>

#include <Astro/orbitalElementConversions.hpp>
#include <Atom/convertCartesianStateToTwoLineElements.hpp>

#include "CppProject/randomKepElem.hpp"

typedef double Real;
typedef std::vector< Real > Vector6;
typedef std::vector< Real > Vector3;
typedef std::vector< Real > Vector2;
typedef std::vector < std::vector < Real > > Vector2D;

int main(void)
{
    // some constants values are defined here
    // earth radius
    // grav. parameter 'mu' of earth
    // value of Pi

	// initialize input parameters for the function generating random orbital elements. Description can be
    // found in randomKepElem.hpp for each of the following parameters.
    const Vector2 range_a      = { 0, 10 };
    const Vector2 range_e      = { 20, 30 };
    const Vector2 range_i      = { 40, 50 };
    const Vector2 range_raan   = { 60, 70 };
    const Vector2 range_w      = { 80, 90 };
    const Vector2 range_E      = { 100, 110 };
    const int limit            = 100;
    Vector2D randKepElem( limit, std::vector< Real >( 6 ) );

    // call the function to generate random keplerian orbital elements. Values are stored in randKepElem in a 2D
    // vector format. A single row represents one set of orbital elements, arranged in the same order as the
    // input argument order of the elements.
    randomKepElem::randomKepElem( range_a, range_e, range_i, range_raan, range_w, range_E, limit, randKepElem );

    // test output to check if the random numbers are generated without any errors
    std::cout << randKepElem[ 0 ][ 1 ] << std::endl;

    //store randomly generated keplerian element sets into a CSV file for easy viewing and use in future debugging of ATOM
    std::ofstream RandomKepElemFile;
    RandomKepElemFile.open("RandomKepElemFile.csv"); //file will be overwritten each time the code is run unless the name is changed here and the code recompiled
    RandomKepElemFile << "semi-major axis [km]" << "," << "eccentricity" << ",";
    RandomKepElemFile << "Inclination [deg]" << "," << "RAAN [deg]" << ",";
    RandomKepElemFile << "AOP [deg]" << "," << "Eccentric Anomaly [deg]" << std::endl;
    for(int i = 0; i < limit; i++)
    {
        for(int j = 0; j < 6; j++)
        {
            RandomKepElemFile << randKepElem[ i ][ j ] << ",";
        }
        RandomKepElemFile << std::endl;
    }
    RandomKepElemFile.close();

    // generate sets of cartesian elements corresponding to each of the psuedo random orbital element set.
    // The conversion from keplerian elements to the cartesian elements is done using the PyKep library from ESA.

	// Tle convertedTle = atom::convertCartesianStateToTwoLineElements< Real, Vector6 >( cartesianState, DateTime( ) );

	// std::cout << convertedTle << std::endl;

    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>///
/// @file  AC_mpi.cpp
/// @brief Implementation of the A + C formulas (from Xavier Gourdon's
///        algorithm) that have been distributed using MPI (Message
///        Passing Interface) and multi-threaded using OpenMP.
///
/// Copyright (C) 2021 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <PiTable.hpp>
#include <SegmentedPiTable.hpp>
#include <primecount-internal.hpp>
#include <mpi_reduce_sum.hpp>
#include <fast_div.hpp>
#include <for_atomic.hpp>
#include <generate.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <print.hpp>
#include <StatusAC.hpp>

#include <stdint.h>
#include <atomic>
#include <vector>

using namespace std;
using namespace primecount;

namespace {

/// Compute the A formula.
/// pi[x_star] < b <= pi[x^(1/3)]
/// x / (primes[b] * primes[i]) < x^(1/2)
///
template <typename T,
          typename Primes>
T A(T x,
    T xlow,
    T xhigh,
    uint64_t y,
    uint64_t b,
    const Primes& primes,
    const PiTable& pi,
    const SegmentedPiTable& segmentedPi)
{
  T sum = 0;

  uint64_t prime = primes[b];
  T xp = x / prime;
  uint64_t sqrt_xp = (uint64_t) isqrt(xp);
  uint64_t min_2nd_prime = min(xhigh / prime, sqrt_xp);
  uint64_t max_2nd_prime = min(xlow / prime, sqrt_xp);
  uint64_t i = pi[max(prime, min_2nd_prime)] + 1;
  uint64_t max_i1 = pi[min(xp / y, max_2nd_prime)];
  uint64_t max_i2 = pi[max_2nd_prime];

  // x / (p * q) >= y
  for (; i <= max_i1; i++)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    sum += segmentedPi[xpq];
  }

  // x / (p * q) < y
  for (; i <= max_i2; i++)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    sum += segmentedPi[xpq] * 2;
  }

  return sum;
}

/// Compute the 1st part of the C formula.
/// pi[(x/z)^(1/3)] < b <= pi[sqrt(z)]
/// x / (primes[b] * m) <= z
///
/// m may be a prime <= y or a square free number <= z which is
/// coprime to the first b primes and whose largest prime factor <= y.
/// This algorithm recursively iterates over the square free numbers
/// coprime to the first b primes. This algorithm is described in
/// section 2.2 of the paper: Douglas Staple, "The Combinatorial
/// Algorithm For Computing pi(x)", arXiv:1503.01839, 6 March 2015.
///
template <int MU,
          typename T,
          typename Primes>
T C1(T xp,
     uint64_t b,
     uint64_t i,
     uint64_t pi_y,
     uint64_t m,
     uint64_t min_m,
     uint64_t max_m,
     const Primes& primes,
     const PiTable& pi)
{
  T sum = 0;

  for (i++; i <= pi_y; i++)
  {
    // Calculate next m
    T m128 = (T) m * primes[i];
    if (m128 > max_m)
      return sum;

    uint64_t m64 = (uint64_t) m128;

    if (m64 > min_m) {
      uint64_t xpm = fast_div64(xp, m64);
      T phi_xpm = pi[xpm] - b + 2;
      sum += phi_xpm * MU;
    }

    sum += C1<-MU>(xp, b, i, pi_y, m64, min_m, max_m, primes, pi);
  }

  return sum;
}

/// Compute the 2nd part of the C formula.
/// pi[sqrt(z)] < b <= pi[x_star]
/// x / (primes[b] * primes[i]) < x^(1/2)
///
template <typename T,
          typename Primes>
T C2(T x,
     T xlow,
     T xhigh,
     uint64_t y,
     uint64_t b,
     const Primes& primes,
     const PiTable& pi,
     const SegmentedPiTable& segmentedPi)
{
  T sum = 0;

  uint64_t prime = primes[b];
  T xp = x / prime;
  uint64_t max_m = min3(xlow / prime, xp / prime, y);
  T min_m128 = max3(xhigh / prime, xp / (prime * prime), prime);
  uint64_t min_m = min(min_m128, max_m);
  uint64_t i = pi[max_m];
  uint64_t pi_min_m = pi[min_m];
  uint64_t min_clustered = (uint64_t) isqrt(xp);
  min_clustered = in_between(min_m, min_clustered, max_m);
  uint64_t pi_min_clustered = pi[min_clustered];

  // Find all clustered easy leaves where
  // successive leaves are identical.
  // n = primes[b] * primes[i]
  // Which satisfy: n > z && primes[i] <= y
  while (i > pi_min_clustered)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    uint64_t phi_xpq = segmentedPi[xpq] - b + 2;
    uint64_t xpq2 = fast_div64(xp, primes[b + phi_xpq - 1]);
    uint64_t i2 = segmentedPi[xpq2];
    sum += phi_xpq * (i - i2);
    i = i2;
  }

  // Find all sparse easy leaves where
  // successive leaves are different.
  // n = primes[b] * primes[i]
  // Which satisfy: n > z && primes[i] <= y
  for (; i > pi_min_m; i--)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    sum += segmentedPi[xpq] - b + 2;
  }

  return sum;
}

/// Compute A + C
template <typename T,
          typename Primes>
T AC_OpenMP(T x,
            int64_t y,
            int64_t z,
            int64_t k,
            int64_t x_star,
            int64_t max_a_prime,
            const Primes& primes,
            int threads)
{
  T sum = 0;
  int64_t x13 = iroot<3>(x);
  int64_t sqrtx = isqrt(x);
  int64_t thread_threshold = 1000;
  threads = ideal_num_threads(threads, x13, thread_threshold);
  StatusAC status(x);

  // PiTable's size >= z because of the C1 formula.
  // We could use segmentation for the C1 formula but this
  // would not increase overall performance (because C1
  // computes very quickly) and the overall memory usage
  // would also not much be reduced.
  PiTable pi(max(z, max_a_prime), threads);

  // SegmentedPiTable's size >= y because of the C2 formula.
  // The C2 algorithm can be modified to work with smaller segment
  // sizes such as x^(1/3) which improves the cache efficiency.
  // However using a segment size < y deteriorates the algorithm's
  // runtime complexity by a factor of log(x).
  SegmentedPiTable segmentedPi(sqrtx, y, threads);

  int64_t pi_y = pi[y];
  int64_t pi_sqrtz = pi[isqrt(z)];
  int64_t pi_x_star = pi[x_star];
  int64_t pi_x13 = pi[x13];
  int64_t pi_root3_xy = pi[iroot<3>(x / y)];
  int64_t pi_root3_xz = pi[iroot<3>(x / z)];
  int64_t min_c1 = max(k, pi_root3_xz) + 1;
  int proc_id = mpi_proc_id();
  int procs = mpi_num_procs();

  atomic<int64_t> atomic_a(-1);
  atomic<int64_t> atomic_c1(-1);
  atomic<int64_t> atomic_c2(-1);

  // In order to reduce the thread creation & destruction
  // overhead we reuse the same threads throughout the
  // entire computation. The same threads are used for:
  //
  // 1) Computation of the C1 formula.
  // 2) Initialization of the segmentedPi lookup table.
  // 3) Computation of the C2 formula.
  // 4) Computation of the A formula.
  //
  #pragma omp parallel num_threads(threads) reduction(+: sum)
  {
    // C1 formula: pi[(x/z)^(1/3)] < b <= pi[pi_sqrtz]
    for_atomic_add(min_c1 + proc_id, b <= pi_sqrtz, procs, atomic_c1)
    {
      int64_t prime = primes[b];
      T xp = x / prime;
      int64_t max_m = min(xp / prime, z);
      T min_m128 = max(xp / (prime * prime), z / prime);
      int64_t min_m = min(min_m128, max_m);

      sum -= C1<-1>(xp, b, b, pi_y, 1, min_m, max_m, primes, pi);
      status.print(b, pi_x13);
    }

    // This computes A and the 2nd part of the C formula.
    // Find all special leaves of type:
    // x / (primes[b] * primes[i]) < x^(1/2)
    // where b is bounded by pi[z^(1/2)] < b <= pi[x^(1/3)].
    // Since we need to lookup PrimePi[n] values for n < x^(1/2)
    // we use a segmented PrimePi[n] table of size y
    // (y = O(x^(1/3) * log(x)^3)) to reduce the memory usage.
    while (segmentedPi.low() < sqrtx)
    {
      // Current segment [low, high[
      segmentedPi.init();
      int64_t low = segmentedPi.low();
      int64_t high = segmentedPi.high();
      T xlow = x / max(low, 1);
      T xhigh = x / high;

      int64_t min_c2 = max(k, pi_root3_xy);
      min_c2 = max(min_c2, pi_sqrtz);
      min_c2 = max(min_c2, pi[isqrt(low)]);
      min_c2 = max(min_c2, pi[min(xhigh / y, x_star)]);
      min_c2 += 1;

      // Upper bound of A & C2 formulas:
      // x / (p * q) >= low
      // p * next_prime(p) <= x / low
      // p <= sqrt(x / low)
      T sqrt_xlow = isqrt(xlow);
      int64_t max_c2 = pi[min(sqrt_xlow, x_star)];
      int64_t max_b = pi[min(sqrt_xlow, x13)];

      // C2 formula: pi[sqrt(z)] < b <= pi[x_star]
      for_atomic_add(min_c2 + proc_id, b <= max_c2, procs, atomic_c2)
      {
        sum += C2(x, xlow, xhigh, y, b, primes, pi, segmentedPi);
        status.print(b, max_b);
      }

      // A formula: pi[x_star] < b <= pi[x13]
      for_atomic_add(pi_x_star + 1 + proc_id, b <= max_b, procs, atomic_a)
      {
        sum += A(x, xlow, xhigh, y, b, primes, pi, segmentedPi);
        status.print(b, max_b);
      }

      // Is this the last segment?
      if (high >= sqrtx)
        break;

      // Wait until all threads have finished
      // computing the current segment.
      #pragma omp barrier
      #pragma omp master
      {
        segmentedPi.next();
        status.next();
        atomic_a = -1;
        atomic_c2 = -1;
      }

      #pragma omp barrier
    }
  }

  sum = mpi_reduce_sum(sum);

  return sum;
}

} // namespace

namespace primecount {

int64_t AC_mpi(int64_t x,
               int64_t y,
               int64_t z,
               int64_t k,
               int threads)
{
  print("");
  print("=== AC_mpi(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  int64_t x_star = get_x_star_gourdon(x, y);
  int64_t max_c_prime = y;
  int64_t max_a_prime = (int64_t) isqrt(x / x_star);
  int64_t max_prime = max(max_a_prime, max_c_prime);
  auto primes = generate_primes<uint32_t>(max_prime);

  int64_t sum = AC_OpenMP((uint64_t) x, y, z, k, x_star, max_a_prime, primes, threads);

  print("A + C", sum, time);
  return sum;
}

#ifdef HAVE_INT128_T

int128_t AC_mpi(int128_t x,
                int64_t y,
                int64_t z,
                int64_t k,
                int threads)
{
  print("");
  print("=== AC_mpi(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  int64_t x_star = get_x_star_gourdon(x, y);
  int64_t max_c_prime = y;
  int64_t max_a_prime = (int64_t) isqrt(x / x_star);
  int64_t max_prime = max(max_a_prime, max_c_prime);
  int128_t sum;

  // uses less memory
  if (max_prime <= numeric_limits<uint32_t>::max())
  {
    auto primes = generate_primes<uint32_t>(max_prime);
    sum = AC_OpenMP((uint128_t) x, y, z, k, x_star, max_a_prime, primes, threads);
  }
  else
  {
    auto primes = generate_primes<uint64_t>(max_prime);
    sum = AC_OpenMP((uint128_t) x, y, z, k, x_star, max_a_prime, primes, threads);
  }

  print("A + C", sum, time);
  return sum;
}

#endif

} // namespace
<commit_msg>Update to new algo<commit_after>///
/// @file  AC_mpi.cpp
/// @brief Implementation of the A + C formulas (from Xavier Gourdon's
///        algorithm) that have been distributed using MPI (Message
///        Passing Interface) and multi-threaded using OpenMP.
///
/// Copyright (C) 2021 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <PiTable.hpp>
#include <SegmentedPiTable.hpp>
#include <primecount-internal.hpp>
#include <LoadBalancerAC.hpp>
#include <mpi_reduce_sum.hpp>
#include <fast_div.hpp>
#include <for_atomic.hpp>
#include <generate.hpp>
#include <int128_t.hpp>
#include <min.hpp>
#include <imath.hpp>
#include <print.hpp>
#include <StatusAC.hpp>

#include <stdint.h>
#include <atomic>
#include <vector>

using namespace std;
using namespace primecount;

namespace {

/// Compute the A formula.
/// pi[x_star] < b <= pi[x^(1/3)]
/// x / (primes[b] * primes[i]) < x^(1/2)
///
template <typename T,
          typename Primes>
T A(T x,
    T xlow,
    T xhigh,
    uint64_t y,
    uint64_t b,
    const Primes& primes,
    const PiTable& pi,
    const SegmentedPiTable& segmentedPi)
{
  T sum = 0;

  uint64_t prime = primes[b];
  T xp = x / prime;
  uint64_t sqrt_xp = (uint64_t) isqrt(xp);
  uint64_t min_2nd_prime = min(xhigh / prime, sqrt_xp);
  uint64_t max_2nd_prime = min(xlow / prime, sqrt_xp);
  uint64_t i = pi[max(prime, min_2nd_prime)] + 1;
  uint64_t max_i1 = pi[min(xp / y, max_2nd_prime)];
  uint64_t max_i2 = pi[max_2nd_prime];

  // x / (p * q) >= y
  for (; i <= max_i1; i++)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    sum += segmentedPi[xpq];
  }

  // x / (p * q) < y
  for (; i <= max_i2; i++)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    sum += segmentedPi[xpq] * 2;
  }

  return sum;
}

/// Compute the 1st part of the C formula.
/// pi[(x/z)^(1/3)] < b <= pi[sqrt(z)]
/// x / (primes[b] * m) <= z
///
/// m may be a prime <= y or a square free number <= z which is
/// coprime to the first b primes and whose largest prime factor <= y.
/// This algorithm recursively iterates over the square free numbers
/// coprime to the first b primes. This algorithm is described in
/// section 2.2 of the paper: Douglas Staple, "The Combinatorial
/// Algorithm For Computing pi(x)", arXiv:1503.01839, 6 March 2015.
///
template <int MU,
          typename T,
          typename Primes>
T C1(T xp,
     uint64_t b,
     uint64_t i,
     uint64_t pi_y,
     uint64_t m,
     uint64_t min_m,
     uint64_t max_m,
     const Primes& primes,
     const PiTable& pi)
{
  T sum = 0;

  for (i++; i <= pi_y; i++)
  {
    // Calculate next m
    T m128 = (T) m * primes[i];
    if (m128 > max_m)
      return sum;

    uint64_t m64 = (uint64_t) m128;

    if (m64 > min_m) {
      uint64_t xpm = fast_div64(xp, m64);
      T phi_xpm = pi[xpm] - b + 2;
      sum += phi_xpm * MU;
    }

    sum += C1<-MU>(xp, b, i, pi_y, m64, min_m, max_m, primes, pi);
  }

  return sum;
}

/// Compute the 2nd part of the C formula.
/// pi[sqrt(z)] < b <= pi[x_star]
/// x / (primes[b] * primes[i]) < x^(1/2)
///
template <typename T,
          typename Primes>
T C2(T x,
     T xlow,
     T xhigh,
     uint64_t y,
     uint64_t b,
     const Primes& primes,
     const PiTable& pi,
     const SegmentedPiTable& segmentedPi)
{
  T sum = 0;

  uint64_t prime = primes[b];
  T xp = x / prime;
  uint64_t max_m = min3(xlow / prime, xp / prime, y);
  T min_m128 = max3(xhigh / prime, xp / (prime * prime), prime);
  uint64_t min_m = min(min_m128, max_m);
  uint64_t i = pi[max_m];
  uint64_t pi_min_m = pi[min_m];
  uint64_t min_clustered = (uint64_t) isqrt(xp);
  min_clustered = in_between(min_m, min_clustered, max_m);
  uint64_t pi_min_clustered = pi[min_clustered];

  // Find all clustered easy leaves where
  // successive leaves are identical.
  // n = primes[b] * primes[i]
  // Which satisfy: n > z && primes[i] <= y
  while (i > pi_min_clustered)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    uint64_t phi_xpq = segmentedPi[xpq] - b + 2;
    uint64_t xpq2 = fast_div64(xp, primes[b + phi_xpq - 1]);
    uint64_t i2 = pi[max(xpq2, min_clustered)];
    sum += phi_xpq * (i - i2);
    i = i2;
  }

  // Find all sparse easy leaves where
  // successive leaves are different.
  // n = primes[b] * primes[i]
  // Which satisfy: n > z && primes[i] <= y
  for (; i > pi_min_m; i--)
  {
    uint64_t xpq = fast_div64(xp, primes[i]);
    sum += segmentedPi[xpq] - b + 2;
  }

  return sum;
}

/// Compute A + C
template <typename T,
          typename Primes>
T AC_OpenMP(T x,
            int64_t y,
            int64_t z,
            int64_t k,
            int64_t x_star,
            int64_t max_a_prime,
            const Primes& primes,
            bool is_print,
            int threads)
{
  T sum = 0;
  int64_t x13 = iroot<3>(x);
  int64_t sqrtx = isqrt(x);
  int64_t thread_threshold = 1000;
  threads = ideal_num_threads(threads, x13, thread_threshold);
  LoadBalancerAC loadBalancer(sqrtx, x13, y, threads);
  StatusAC status(is_print);

  // PiTable's size = z because of the C1 formula.
  // PiTable is accessed much less frequently than
  // SegmentedPiTable, hence it is OK that PiTable's size
  // is fairly large and does not fit into the CPU's cache.
  PiTable pi(max(z, max_a_prime), threads);

  int64_t pi_y = pi[y];
  int64_t pi_sqrtz = pi[isqrt(z)];
  int64_t pi_root3_xy = pi[iroot<3>(x / y)];
  int64_t pi_root3_xz = pi[iroot<3>(x / z)];
  int64_t min_c1 = max(k, pi_root3_xz) + 1;
  atomic<int64_t> atomic_c1(-1);
  int proc_id = mpi_proc_id();
  int procs = mpi_num_procs();

  // In order to reduce the thread creation & destruction
  // overhead we reuse the same threads throughout the
  // entire computation. The same threads are used for:
  //
  // 1) Computation of the C1 formula.
  // 2) Computation of the C2 formula.
  // 3) Computation of the A formula.
  //
  #pragma omp parallel num_threads(threads) reduction(+: sum)
  {
    // SegmentedPiTable is accessed very frequently.
    // In order to get good performance it is important that
    // SegmentedPiTable fits into the CPU's cache.
    // Hence we use a small segment_size of x^(1/4).
    SegmentedPiTable segmentedPi;
    int64_t low, high;

    // C1 formula: pi[(x/z)^(1/3)] < b <= pi[pi_sqrtz]
    for_atomic_add(min_c1 + proc_id, b <= pi_sqrtz, procs, atomic_c1)
    {
      int64_t prime = primes[b];
      T xp = x / prime;
      int64_t max_m = min(xp / prime, z);
      T min_m128 = max(xp / (prime * prime), z / prime);
      int64_t min_m = min(min_m128, max_m);

      sum -= C1<-1>(xp, b, b, pi_y, 1, min_m, max_m, primes, pi);
    }

    // for (low = 0; low < sqrt; low += segment_size)
    while (loadBalancer.get_work(low, high))
    {
      // Current segment [low, high[
      status.print(low, sqrtx, high - low);
      segmentedPi.init(low, high);
      T xlow = x / max(low, 1);
      T xhigh = x / high;

      int64_t min_c2 = max(k, pi_root3_xy);
      min_c2 = max(min_c2, pi_sqrtz);
      min_c2 = max(min_c2, pi[isqrt(low)]);
      min_c2 = max(min_c2, pi[min(xhigh / y, x_star)]);
      min_c2 += 1;

      int64_t min_a = min(xhigh / high, x13);
      min_a = pi[max(x_star, min_a)] + 1;

      // Upper bound of A & C2 formulas:
      // x / (p * q) >= low
      // p * next_prime(p) <= x / low
      // p <= sqrt(x / low)
      T sqrt_xlow = isqrt(xlow);
      int64_t max_c2 = pi[min(sqrt_xlow, x_star)];
      int64_t max_a = pi[min(sqrt_xlow, x13)];

      // C2 formula: pi[sqrt(z)] < b <= pi[x_star]
      for (int64_t b = min_c2 + proc_id; b <= max_c2; b += procs)
        sum += C2(x, xlow, xhigh, y, b, primes, pi, segmentedPi);

      // A formula: pi[x_star] < b <= pi[x13]
      for (int64_t b = min_a + proc_id; b <= max_a; b += procs)
        sum += A(x, xlow, xhigh, y, b, primes, pi, segmentedPi);
    }
  }

  sum = mpi_reduce_sum(sum);

  return sum;
}

} // namespace

namespace primecount {

int64_t AC_mpi(int64_t x,
               int64_t y,
               int64_t z,
               int64_t k,
               int threads)
{
  print("");
  print("=== AC_mpi(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  int64_t x_star = get_x_star_gourdon(x, y);
  int64_t max_c_prime = y;
  int64_t max_a_prime = (int64_t) isqrt(x / x_star);
  int64_t max_prime = max(max_a_prime, max_c_prime);
  auto primes = generate_primes<uint32_t>(max_prime);

  int64_t sum = AC_OpenMP((uint64_t) x, y, z, k, x_star, max_a_prime, primes, is_print(), threads);

  print("A + C", sum, time);
  return sum;
}

#ifdef HAVE_INT128_T

int128_t AC_mpi(int128_t x,
                int64_t y,
                int64_t z,
                int64_t k,
                int threads)
{
  print("");
  print("=== AC_mpi(x, y) ===");
  print_gourdon_vars(x, y, z, k, threads);

  double time = get_time();
  int64_t x_star = get_x_star_gourdon(x, y);
  int64_t max_c_prime = y;
  int64_t max_a_prime = (int64_t) isqrt(x / x_star);
  int64_t max_prime = max(max_a_prime, max_c_prime);
  int128_t sum;

  // uses less memory
  if (max_prime <= numeric_limits<uint32_t>::max())
  {
    auto primes = generate_primes<uint32_t>(max_prime);
    sum = AC_OpenMP((uint128_t) x, y, z, k, x_star, max_a_prime, primes, is_print(), threads);
  }
  else
  {
    auto primes = generate_primes<uint64_t>(max_prime);
    sum = AC_OpenMP((uint128_t) x, y, z, k, x_star, max_a_prime, primes, is_print(), threads);
  }

  print("A + C", sum, time);
  return sum;
}

#endif

} // namespace
<|endoftext|>


<commit_before>/*
====================================================================
Copyright (c) 2011 Ian Blumel.  All rights reserved.

This software is licensed as described in the file LICENSE, which
you should have received as part of this distribution.
====================================================================
File: test_chk_ex.cxx
*/

#include "fct.h"

class err_t {};
class sub_err_t : err_t {};
class other_err_t {};

static void throw_err() {
   throw err_t();
}

static void throw_sub_err() {
   throw sub_err_t();
}

static void throw_other_err() {
   throw other_err_t();
}

static void not_going_to_throw() {
  int j = 2+1;
  char buf[32];
  sprintf(buf, "j=%d", j);
}

FCT_BGN()
{
    FCT_QTEST_BGN(throw_err) {
       fct_chk_ex(
           err_t,
           throw_err()
       );
    } FCT_QTEST_END();

    FCT_QTEST_BGN(throw_and_catch_sub_err) {
       fct_chk_ex(
           sub_err_t,
           throw_sub_err()
       );
    } FCT_QTEST_END();

    FCT_QTEST_BGN(throw_and_catch_other_err__should_fail) {
       /* This is checking for an exception of type "sub_err_t", but
       doesn't get it. Should fail! */
       fct_chk_ex(
           sub_err_t,
           throw_other_err()
       );
    } FCT_QTEST_END();

    FCT_QTEST_BGN(doesnt_throw) {
       /* This is expecting the function to throw an error, but it
       doesn't. */
       fct_chk_ex(
           err_t,
           not_going_to_throw();
       );
    } FCT_QTEST_END();

    printf("\n***TESTS ARE SUPPOSED TO REPORT FAILURES***\n");
    FCT_EXPECTED_FAILURES(2);
}
FCT_END();
<commit_msg>quite warnings with fct_chk_ex and MSVC.<commit_after>/*
====================================================================
Copyright (c) 2011 Ian Blumel.  All rights reserved.

This software is licensed as described in the file LICENSE, which
you should have received as part of this distribution.
====================================================================
File: test_chk_ex.cxx
*/

#include "fct.h"

class err_t {};
class sub_err_t : public err_t {};
class other_err_t {};

static void throw_err() {
   throw err_t();
}

static void throw_sub_err() {
   throw sub_err_t();
}

static void throw_other_err() {
   throw other_err_t();
}

static void not_going_to_throw() {
  int j = 2+1;
  char buf[32];
  fct_snprintf(buf, sizeof(buf), "j=%d", j);
}

FCT_BGN()
{
    FCT_QTEST_BGN(throw_err) {
       fct_chk_ex(
           err_t&,
           throw_err()
       );
    } FCT_QTEST_END();

    FCT_QTEST_BGN(throw_and_catch_sub_err) {
       fct_chk_ex(
           sub_err_t&,
           throw_sub_err()
       );
    } FCT_QTEST_END();

    FCT_QTEST_BGN(throw_and_catch_other_err__should_fail) {
       /* This is checking for an exception of type "sub_err_t", but
       doesn't get it. Should fail! */
       fct_chk_ex(
           sub_err_t&,
           throw_other_err()
       );
    } FCT_QTEST_END();

    FCT_QTEST_BGN(doesnt_throw) {
       /* This is expecting the function to throw an error, but it
       doesn't. */
       fct_chk_ex(
           err_t&,
           not_going_to_throw();
       );
    } FCT_QTEST_END();

    printf("\n***TESTS ARE SUPPOSED TO REPORT FAILURES***\n");
    FCT_EXPECTED_FAILURES(2);
}
FCT_END();
<|endoftext|>


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

#include <iostream>
#include <string>

#include "loopp/ble/BLEScanner.hpp"
#include "loopp/core/MainLoop.hpp"
#include "loopp/core/Slot.hpp"
#include "loopp/core/Task.hpp"
#include "loopp/http/HttpClient.hpp"
#include "loopp/mqtt/MqttClient.hpp"
#include "loopp/net/Wifi.hpp"
#include "loopp/utils/hexdump.hpp"
#include "loopp/utils/json.hpp"

#include "string.h"

extern "C"
{
#include "esp_heap_trace.h"
}
#include "driver/gpio.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "nvs_flash.h"

#include "user_config.h"

using json = nlohmann::json;

static const char tag[] = "BEACON-SCANNER";

extern const uint8_t ca_start[] asm("_binary_CA_crt_start");
extern const uint8_t ca_end[] asm("_binary_CA_crt_end");
extern const uint8_t certificate_start[] asm("_binary_esp32_crt_start");
extern const uint8_t certificate_end[] asm("_binary_esp32_crt_end");
extern const uint8_t private_key_start[] asm("_binary_esp32_key_start");
extern const uint8_t private_key_end[] asm("_binary_esp32_key_end");

// #define NUM_RECORDS 100
// static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM

class Main
{
public:
  Main()
    : beacon_scanner(loopp::ble::BLEScanner::instance()), wifi(loopp::net::Wifi::instance()),
      loop(std::make_shared<loopp::core::MainLoop>()),
      mqtt(std::make_shared<loopp::mqtt::MqttClient>(loop, "BLEScanner", MQTT_HOST, MQTT_PORT)),
      task("main_task", std::bind(&Main::main_task, this))
  {
    gpio_pad_select_gpio(LED_GPIO);
    gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);

    std::string mac = wifi.get_mac();
    topic_config = "beaconscanner/config/" + mac;
    topic_scan = "beaconscanner/scan/" + mac;
  }

private:
  // https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
  static std::string
  base64_encode(const std::string &in)
  {
    std::string out;

    int val = 0, valb = -6;
    for (char c : in)
      {
        val = (val << 8) + c;
        valb += 8;
        while (valb >= 0)
          {
            out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
            valb -= 6;
          }
      }
    if (valb > -6)
      out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
    while (out.size() % 4)
      out.push_back('=');
    return out;
  }

  read_body(std::shared_ptr<loopp::http::HttpClient> client)
  {
    client->read_body_async(1024, loopp::core::make_slot(loop, [this, client](std::error_code, loopp::net::StreamBuffer *buffer) {
          if (buffer->consume_size() > 0)
          {
            std::string s(buffer->consume_data(), buffer->consume_size());
            buffer->consume_commit(buffer->consume_size());
            ESP_LOGI(tag, "Body: %s", s.c_str());
            read_body(client);
          }
        }));
  }

  void
  test_http()
  {
    std::shared_ptr<loopp::http::HttpClient> client = std::make_shared<loopp::http::HttpClient>(loop);

    client->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
    client->set_ca_certificate(reinterpret_cast<const char *>(ca_start));

    loopp::http::Request request("GET", "https://" MQTT_HOST ":443/");
    client->execute(request, loopp::core::make_slot(loop, [this, client](std::error_code, loopp::http::Response) { read_body(client); }));
  }

  void
  on_wifi_system_event(system_event_t event)
  {
    ESP_LOGI(tag, "-> System event %d", event.event_id);
  }

  void
  on_wifi_timeout()
  {
    ESP_LOGI(tag, "-> Wifi timer");
    wifi_timer = 0;
    if (!wifi.connected().get())
      {
        ESP_LOGI(tag, "-> Wifi failed to connect in time. Reset");
        wifi.reconnect();
        wifi_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
      }
  }

  void
  on_wifi_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> Wifi connected");
        loop->cancel_timer(wifi_timer);
#ifdef MQTT_USER
        mqtt->set_username(MQTT_USER);
#endif
#ifdef MQTT_PASS
        mqtt->set_password(MQTT_PASS);
#endif
#ifdef MQTT_USE_TLS
        mqtt->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
        mqtt->set_ca_certificate(reinterpret_cast<const char *>(ca_start));
#endif
        mqtt->set_callback(loopp::core::make_slot(loop, [this](std::string topic, std::string payload) { on_mqtt_data(topic, payload); }));
        mqtt->connected().connect(loop, std::bind(&Main::on_mqtt_connected, this, std::placeholders::_1));
        mqtt->connect();

        test_http();
      }
    else
      {
        ESP_LOGI(tag, "-> Wifi disconnected");
      }
  }

  void
  on_mqtt_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> MQTT connected");
        ESP_LOGI(tag, "-> Requesting configuration at %s", topic_config.c_str());
        mqtt->subscribe(topic_config);
        mqtt->add_filter(topic_config,
                         loopp::core::make_slot(loop, [this](std::string topic, std::string payload) { on_provisioning(payload); }));
        start_beacon_scan();
      }
    else
      {
        ESP_LOGI(tag, "-> MQTT disconnected");
        stop_beacon_scan();
      }
  }

  void
  on_mqtt_data(std::string topic, std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT %s -> %s (free %d)", topic.c_str(), payload.c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
  }

  void
  on_provisioning(std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT provisioning-> %s (free %d)", payload.c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));

    // TODO:
    // beacon_scanner.start();
  }

  void
  on_beacon_scanner_scan_result(loopp::ble::BLEScanner::ScanResult result)
  {
    static int led_state = 0;

    led_state ^= 1;
    gpio_set_level(LED_GPIO, led_state);
    scan_results.push_back(result);
  }

  void
  on_scan_timer()
  {
    json j;

    if (mqtt->connected().get())
      {
        for (auto r : scan_results)
          {
            ESP_LOGI(tag, "on_scan_timer %s (free %d)", r.bda_as_string().c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
            json jb;
            jb["mac"] = r.bda_as_string();
            jb["bda"] = base64_encode(std::string(reinterpret_cast<char *>(r.bda), sizeof(r.bda)));
            jb["rssi"] = r.rssi;
            jb["adv_data"] = base64_encode(r.adv_data);
            j.push_back(jb);
          }

        mqtt->publish(topic_scan, j.dump());
      }
    scan_results.clear();
  }

  void
  start_beacon_scan()
  {
    scan_timer = loop->add_periodic_timer(std::chrono::milliseconds(1000), std::bind(&Main::on_scan_timer, this));
    beacon_scanner.start();
  }

  void
  stop_beacon_scan()
  {
    loop->cancel_timer(scan_timer);
    scan_timer = 0;

    beacon_scanner.stop();
  }

  void
  main_task()
  {
    wifi.set_ssid(WIFI_SSID);
    wifi.set_passphase(WIFI_PASS);
    wifi.set_host_name("scan");
    wifi.set_auto_connect(true);
    wifi.system_event_signal().connect(loop, std::bind(&Main::on_wifi_system_event, this, std::placeholders::_1));
    wifi.connected().connect(loop, std::bind(&Main::on_wifi_connected, this, std::placeholders::_1));

    beacon_scanner.scan_result_signal().connect(loop, std::bind(&Main::on_beacon_scanner_scan_result, this, std::placeholders::_1));

    wifi_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
    wifi.connect();

    heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);
    // heap_trace_init_standalone(trace_record, NUM_RECORDS);
    // ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_ALL) );

    loop->run();
  }

  loopp::ble::BLEScanner &beacon_scanner;
  loopp::net::Wifi &wifi;
  std::shared_ptr<loopp::core::MainLoop> loop;
  std::shared_ptr<loopp::mqtt::MqttClient> mqtt;
  loopp::core::Task task;
  loopp::core::MainLoop::timer_id wifi_timer = 0;
  loopp::core::MainLoop::timer_id scan_timer = 0;
  std::list<loopp::ble::BLEScanner::ScanResult> scan_results;
  std::string topic_config;
  std::string topic_scan;

  const static gpio_num_t LED_GPIO = GPIO_NUM_5;
};

extern "C" void
app_main()
{
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
    {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
  ESP_ERROR_CHECK(ret);

  ESP_LOGI(tag, "HEAP: startup");
  heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);

  new Main();

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

#include <iostream>
#include <string>

#include "loopp/ble/BLEScanner.hpp"
#include "loopp/core/MainLoop.hpp"
#include "loopp/core/Slot.hpp"
#include "loopp/core/Task.hpp"
#include "loopp/http/HttpClient.hpp"
#include "loopp/mqtt/MqttClient.hpp"
#include "loopp/net/Wifi.hpp"
#include "loopp/utils/hexdump.hpp"
#include "loopp/utils/json.hpp"

#include "string.h"

extern "C"
{
#include "esp_heap_trace.h"
}
#include "driver/gpio.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "nvs_flash.h"

#include "user_config.h"

using json = nlohmann::json;

static const char tag[] = "BEACON-SCANNER";

extern const uint8_t ca_start[] asm("_binary_CA_crt_start");
extern const uint8_t ca_end[] asm("_binary_CA_crt_end");
extern const uint8_t certificate_start[] asm("_binary_esp32_crt_start");
extern const uint8_t certificate_end[] asm("_binary_esp32_crt_end");
extern const uint8_t private_key_start[] asm("_binary_esp32_key_start");
extern const uint8_t private_key_end[] asm("_binary_esp32_key_end");

// #define NUM_RECORDS 100
// static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM

class Main
{
public:
  Main()
    : beacon_scanner(loopp::ble::BLEScanner::instance()), wifi(loopp::net::Wifi::instance()),
      loop(std::make_shared<loopp::core::MainLoop>()),
      mqtt(std::make_shared<loopp::mqtt::MqttClient>(loop, "BLEScanner", MQTT_HOST, MQTT_PORT)),
      task("main_task", std::bind(&Main::main_task, this))
  {
    gpio_pad_select_gpio(LED_GPIO);
    gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);

    std::string mac = wifi.get_mac();
    topic_config = "beaconscanner/config/" + mac;
    topic_scan = "beaconscanner/scan/" + mac;
  }

private:
  // https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
  static std::string
  base64_encode(const std::string &in)
  {
    std::string out;

    int val = 0, valb = -6;
    for (char c : in)
      {
        val = (val << 8) + c;
        valb += 8;
        while (valb >= 0)
          {
            out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
            valb -= 6;
          }
      }
    if (valb > -6)
      out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
    while (out.size() % 4)
      out.push_back('=');
    return out;
  }

  void
  read_body(std::shared_ptr<loopp::http::HttpClient> client)
  {
    client->read_body_async(1024, loopp::core::make_slot(loop, [this, client](std::error_code, loopp::net::StreamBuffer *buffer) {
          if (buffer->consume_size() > 0)
          {
            std::string s(buffer->consume_data(), buffer->consume_size());
            buffer->consume_commit(buffer->consume_size());
            ESP_LOGI(tag, "Body: %s", s.c_str());
            read_body(client);
          }
        }));
  }

  void
  test_http()
  {
    std::shared_ptr<loopp::http::HttpClient> client = std::make_shared<loopp::http::HttpClient>(loop);

    client->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
    client->set_ca_certificate(reinterpret_cast<const char *>(ca_start));

    loopp::http::Request request("GET", "https://" MQTT_HOST ":443/");
    client->execute(request, loopp::core::make_slot(loop, [this, client](std::error_code, loopp::http::Response) { read_body(client); }));
  }

  void
  on_wifi_system_event(system_event_t event)
  {
    ESP_LOGI(tag, "-> System event %d", event.event_id);
  }

  void
  on_wifi_timeout()
  {
    ESP_LOGI(tag, "-> Wifi timer");
    wifi_timer = 0;
    if (!wifi.connected().get())
      {
        ESP_LOGI(tag, "-> Wifi failed to connect in time. Reset");
        wifi.reconnect();
        wifi_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
      }
  }

  void
  on_wifi_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> Wifi connected");
        loop->cancel_timer(wifi_timer);
#ifdef MQTT_USER
        mqtt->set_username(MQTT_USER);
#endif
#ifdef MQTT_PASS
        mqtt->set_password(MQTT_PASS);
#endif
#ifdef MQTT_USE_TLS
        mqtt->set_client_certificate(reinterpret_cast<const char *>(certificate_start), reinterpret_cast<const char *>(private_key_start));
        mqtt->set_ca_certificate(reinterpret_cast<const char *>(ca_start));
#endif
        mqtt->set_callback(loopp::core::make_slot(loop, [this](std::string topic, std::string payload) { on_mqtt_data(topic, payload); }));
        mqtt->connected().connect(loop, std::bind(&Main::on_mqtt_connected, this, std::placeholders::_1));
        mqtt->connect();

        test_http();
      }
    else
      {
        ESP_LOGI(tag, "-> Wifi disconnected");
      }
  }

  void
  on_mqtt_connected(bool connected)
  {
    if (connected)
      {
        ESP_LOGI(tag, "-> MQTT connected");
        ESP_LOGI(tag, "-> Requesting configuration at %s", topic_config.c_str());
        mqtt->subscribe(topic_config);
        mqtt->add_filter(topic_config,
                         loopp::core::make_slot(loop, [this](std::string topic, std::string payload) { on_provisioning(payload); }));
        start_beacon_scan();
      }
    else
      {
        ESP_LOGI(tag, "-> MQTT disconnected");
        stop_beacon_scan();
      }
  }

  void
  on_mqtt_data(std::string topic, std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT %s -> %s (free %d)", topic.c_str(), payload.c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
  }

  void
  on_provisioning(std::string payload)
  {
    ESP_LOGI(tag, "-> MQTT provisioning-> %s (free %d)", payload.c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));

    // TODO:
    // beacon_scanner.start();
  }

  void
  on_beacon_scanner_scan_result(loopp::ble::BLEScanner::ScanResult result)
  {
    static int led_state = 0;

    led_state ^= 1;
    gpio_set_level(LED_GPIO, led_state);
    scan_results.push_back(result);
  }

  void
  on_scan_timer()
  {
    json j;

    if (mqtt->connected().get())
      {
        for (auto r : scan_results)
          {
            ESP_LOGI(tag, "on_scan_timer %s (free %d)", r.bda_as_string().c_str(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT));
            json jb;
            jb["mac"] = r.bda_as_string();
            jb["bda"] = base64_encode(std::string(reinterpret_cast<char *>(r.bda), sizeof(r.bda)));
            jb["rssi"] = r.rssi;
            jb["adv_data"] = base64_encode(r.adv_data);
            j.push_back(jb);
          }

        mqtt->publish(topic_scan, j.dump());
      }
    scan_results.clear();
  }

  void
  start_beacon_scan()
  {
    scan_timer = loop->add_periodic_timer(std::chrono::milliseconds(1000), std::bind(&Main::on_scan_timer, this));
    beacon_scanner.start();
  }

  void
  stop_beacon_scan()
  {
    loop->cancel_timer(scan_timer);
    scan_timer = 0;

    beacon_scanner.stop();
  }

  void
  main_task()
  {
    wifi.set_ssid(WIFI_SSID);
    wifi.set_passphase(WIFI_PASS);
    wifi.set_host_name("scan");
    wifi.set_auto_connect(true);
    wifi.system_event_signal().connect(loop, std::bind(&Main::on_wifi_system_event, this, std::placeholders::_1));
    wifi.connected().connect(loop, std::bind(&Main::on_wifi_connected, this, std::placeholders::_1));

    beacon_scanner.scan_result_signal().connect(loop, std::bind(&Main::on_beacon_scanner_scan_result, this, std::placeholders::_1));

    wifi_timer = loop->add_timer(std::chrono::milliseconds(5000), std::bind(&Main::on_wifi_timeout, this));
    wifi.connect();

    heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);
    // heap_trace_init_standalone(trace_record, NUM_RECORDS);
    // ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_ALL) );

    loop->run();
  }

  loopp::ble::BLEScanner &beacon_scanner;
  loopp::net::Wifi &wifi;
  std::shared_ptr<loopp::core::MainLoop> loop;
  std::shared_ptr<loopp::mqtt::MqttClient> mqtt;
  loopp::core::Task task;
  loopp::core::MainLoop::timer_id wifi_timer = 0;
  loopp::core::MainLoop::timer_id scan_timer = 0;
  std::list<loopp::ble::BLEScanner::ScanResult> scan_results;
  std::string topic_config;
  std::string topic_scan;

  const static gpio_num_t LED_GPIO = GPIO_NUM_5;
};

extern "C" void
app_main()
{
  esp_err_t ret = nvs_flash_init();
  if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
    {
      ESP_ERROR_CHECK(nvs_flash_erase());
      ret = nvs_flash_init();
    }
  ESP_ERROR_CHECK(ret);

  ESP_LOGI(tag, "HEAP: startup");
  heap_caps_print_heap_info(MALLOC_CAP_DEFAULT);

  new Main();

  while (1)
    {
      vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}
<|endoftext|>