<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#include <gtest/gtest.h>
#include <pcl/pcl_tests.h>
#include <pcl/point_types.h>
#include <pcl/common/point_operators.h>

using namespace pcl;
using namespace pcl::test;

//////////////////////////////////////////////////////////////////////////////
TEST (PointOperators, PointXYZ)
{
  using namespace pcl::common;
  PointXYZ p0; p0.x = 0.1f;  p0.y = 0.2f;  p0.z = 0.3f;
  PointXYZ p1; p1.x = 0.05f; p1.y = 0.05f; p1.z = 0.05f;
  PointXYZ p2 = p0;
  p2 += p1;
  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);

  p2 = p0 + p1;

  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);

  PointXYZ p3 = p0 - p1;

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);

  p3 = p0;
  p3 -= p1;

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);

  float scalar = 4;
  p2 *= scalar;

  EXPECT_EQ (p2.x, scalar * p0.x + scalar * p1.x);
  EXPECT_EQ (p2.y, scalar * p0.y + scalar * p1.y);
  EXPECT_EQ (p2.z, scalar * p0.z + scalar * p1.z);

  p2 /= 2;

  EXPECT_EQ (p2.x, scalar / 2.0f * p0.x + scalar / 2.0f * p1.x);
  EXPECT_EQ (p2.y, scalar / 2.0f * p0.y + scalar / 2.0f * p1.y);
  EXPECT_EQ (p2.z, scalar / 2.0f * p0.z + scalar / 2.0f * p1.z);
}

//////////////////////////////////////////////////////////////////////////////
TEST (PointOperators, PointXYZI)
{
  using namespace pcl::common;
  PointXYZI p0; p0.x = 0.1f; p0.y = 0.2f;  p0.z = 0.3f; p0.intensity = 123;
  PointXYZI p1; p1.x = 0.05f; p1.y = 0.05f; p1.z = 0.05f; p1.intensity = 133;
  PointXYZI p2 = p0 + p1;
  PointXYZI p3 = p0 - p1;

  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);
  EXPECT_EQ (p2.intensity, p0.intensity + p1.intensity);

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);
  EXPECT_EQ (p3.intensity, p0.intensity - p1.intensity);

  p2 = 0.1f * p1;
  EXPECT_NEAR (p2.x, 0.1 * p1.x, 1e-4);
  EXPECT_NEAR (p2.y, 0.1 * p1.y, 1e-4);
  EXPECT_NEAR (p2.z, 0.1 * p1.z, 1e-4);
  EXPECT_NEAR (p2.intensity, 0.1 * p1.intensity, 1e-4);
  PointXYZI p4 = p1 * 0.1f;
  EXPECT_EQ_VECTORS (p2.getVector3fMap (), p4.getVector3fMap ());
  EXPECT_EQ (p2.intensity, p4.intensity);
}

//////////////////////////////////////////////////////////////////////////////
TEST (PointOperators, PointXYZRGB)
{
  using namespace pcl::common;
  PointXYZRGB p0; p0.x = 0.1f; p0.y = 0.2f;  p0.z = 0.3f; p0.r = 123; p0.g = 125; p0.b = 127;
  PointXYZRGB p1; p1.x = 0.05f; p1.y = 0.05f; p1.z = 0.05f; p1.r = 123; p1.g = 125; p1.b = 127;
  PointXYZRGB p2 = p0 + p1;
  PointXYZRGB p3 = p0 - p1;

  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);
  EXPECT_EQ (p2.r, p0.r + p1.r);
  EXPECT_EQ (p2.g, p0.g + p1.g);
  EXPECT_EQ (p2.b, p0.b + p1.b);

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);
  EXPECT_EQ (p3.r, p0.r - p1.r);
  EXPECT_EQ (p3.g, p0.g - p1.g);
  EXPECT_EQ (p3.b, p0.b - p1.b);

  p2 = 0.1f * p1;
  EXPECT_NEAR (p2.x, 0.1 * p1.x, 1e-4);
  EXPECT_NEAR (p2.y, 0.1 * p1.y, 1e-4);
  EXPECT_NEAR (p2.z, 0.1 * p1.z, 1e-4);
  EXPECT_EQ (p2.r, static_cast<pcl::uint8_t> (0.1 * p1.r));

  EXPECT_EQ (p2.g, static_cast<pcl::uint8_t> (0.1 * p1.g));
  EXPECT_EQ (p2.b, static_cast<pcl::uint8_t> (0.1 * p1.b));
  PointXYZRGB p4 = p1 * 0.1f;
  EXPECT_EQ_VECTORS (p2.getVector3fMap (), p4.getVector3fMap ());
  EXPECT_EQ (p2.r, p4.r);
  EXPECT_EQ (p2.g, p4.g);
  EXPECT_EQ (p2.b, p4.b);
}

int
main (int argc, char** argv)
{
  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());
}
<commit_msg>disabled unit tests for RGB/color point operators as they don't make any sense at all<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#include <gtest/gtest.h>
#include <pcl/pcl_tests.h>
#include <pcl/point_types.h>
#include <pcl/common/point_operators.h>

using namespace pcl;
using namespace pcl::test;

//////////////////////////////////////////////////////////////////////////////
TEST (PointOperators, PointXYZ)
{
  using namespace pcl::common;
  PointXYZ p0; p0.x = 0.1f;  p0.y = 0.2f;  p0.z = 0.3f;
  PointXYZ p1; p1.x = 0.05f; p1.y = 0.05f; p1.z = 0.05f;
  PointXYZ p2 = p0;
  p2 += p1;
  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);

  p2 = p0 + p1;

  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);

  PointXYZ p3 = p0 - p1;

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);

  p3 = p0;
  p3 -= p1;

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);

  float scalar = 4;
  p2 *= scalar;

  EXPECT_EQ (p2.x, scalar * p0.x + scalar * p1.x);
  EXPECT_EQ (p2.y, scalar * p0.y + scalar * p1.y);
  EXPECT_EQ (p2.z, scalar * p0.z + scalar * p1.z);

  p2 /= 2;

  EXPECT_EQ (p2.x, scalar / 2.0f * p0.x + scalar / 2.0f * p1.x);
  EXPECT_EQ (p2.y, scalar / 2.0f * p0.y + scalar / 2.0f * p1.y);
  EXPECT_EQ (p2.z, scalar / 2.0f * p0.z + scalar / 2.0f * p1.z);
}

//////////////////////////////////////////////////////////////////////////////
TEST (PointOperators, PointXYZI)
{
  using namespace pcl::common;
  PointXYZI p0; p0.x = 0.1f; p0.y = 0.2f;  p0.z = 0.3f; p0.intensity = 123;
  PointXYZI p1; p1.x = 0.05f; p1.y = 0.05f; p1.z = 0.05f; p1.intensity = 133;
  PointXYZI p2 = p0 + p1;
  PointXYZI p3 = p0 - p1;

  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);
  EXPECT_EQ (p2.intensity, p0.intensity + p1.intensity);

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);
  EXPECT_EQ (p3.intensity, p0.intensity - p1.intensity);

  p2 = 0.1f * p1;
  EXPECT_NEAR (p2.x, 0.1 * p1.x, 1e-4);
  EXPECT_NEAR (p2.y, 0.1 * p1.y, 1e-4);
  EXPECT_NEAR (p2.z, 0.1 * p1.z, 1e-4);
  EXPECT_NEAR (p2.intensity, 0.1 * p1.intensity, 1e-4);
  PointXYZI p4 = p1 * 0.1f;
  EXPECT_EQ_VECTORS (p2.getVector3fMap (), p4.getVector3fMap ());
  EXPECT_EQ (p2.intensity, p4.intensity);
}

//////////////////////////////////////////////////////////////////////////////
TEST (PointOperators, PointXYZRGB)
{
  using namespace pcl::common;
  PointXYZRGB p0; p0.x = 0.1f; p0.y = 0.2f;  p0.z = 0.3f; p0.r = 123; p0.g = 125; p0.b = 127;
  PointXYZRGB p1; p1.x = 0.05f; p1.y = 0.05f; p1.z = 0.05f; p1.r = 123; p1.g = 125; p1.b = 127;
  PointXYZRGB p2 = p0 + p1;
  PointXYZRGB p3 = p0 - p1;

  EXPECT_EQ (p2.x, p0.x + p1.x);
  EXPECT_EQ (p2.y, p0.y + p1.y);
  EXPECT_EQ (p2.z, p0.z + p1.z);
  // Disabled. Doesn't make any sense
  //EXPECT_EQ (p2.r, p0.r + p1.r);
  //EXPECT_EQ (p2.g, p0.g + p1.g);
  //EXPECT_EQ (p2.b, p0.b + p1.b);

  EXPECT_EQ (p3.x, p0.x - p1.x);
  EXPECT_EQ (p3.y, p0.y - p1.y);
  EXPECT_EQ (p3.z, p0.z - p1.z);
  // Disabled. Doesn't make any sense
  //EXPECT_EQ (p3.r, p0.r - p1.r);
  //EXPECT_EQ (p3.g, p0.g - p1.g);
  //EXPECT_EQ (p3.b, p0.b - p1.b);

  p2 = 0.1f * p1;
  EXPECT_NEAR (p2.x, 0.1 * p1.x, 1e-4);
  EXPECT_NEAR (p2.y, 0.1 * p1.y, 1e-4);
  EXPECT_NEAR (p2.z, 0.1 * p1.z, 1e-4);
  // Disabled. Doesn't make any sense
  //EXPECT_EQ (p2.r, static_cast<pcl::uint8_t> (0.1 * p1.r));
  //EXPECT_EQ (p2.g, static_cast<pcl::uint8_t> (0.1 * p1.g));
  //EXPECT_EQ (p2.b, static_cast<pcl::uint8_t> (0.1 * p1.b));
  PointXYZRGB p4 = p1 * 0.1f;
  EXPECT_EQ_VECTORS (p2.getVector3fMap (), p4.getVector3fMap ());
  // Disabled. Doesn't make any sense
  //EXPECT_EQ (p2.r, p4.r);
  //EXPECT_EQ (p2.g, p4.g);
  //EXPECT_EQ (p2.b, p4.b);
}

int
main (int argc, char** argv)
{
  testing::InitGoogleTest (&argc, argv);
  return (RUN_ALL_TESTS ());
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (C) 2013 PX4 Development Team. All rights reserved.
 *   Author: Pavel Kirienko <pavel.kirienko@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include <ch.h>
#include <hal.h>
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <config/config.h>
#include <sys.h>
#include <led.h>
#include <console.h>
#include <watchdog.h>
#include <motor/motor.h>
#include <uavcan_node/uavcan_node.hpp>

namespace
{

int init()
{
	int res = 0;

	led_init();
	led_set_rgb(0.05, 0.05, 0.05);

	/*
	 * Config
	 */
	res = config_init();
	if (res) {
		return res;
	}

	/*
	 * Safety
	 */
	watchdog_init();

	/*
	 * UAVCAN node
	 */
	res = uavcan_node::init();
	if (res) {
		return res;
	}

	/*
	 * Motor control
	 */
	::usleep(10000);
	res = motor_init();
	if (res) {
		return res;
	}

	::usleep(10000);
	res = motor_test_hardware();
	if (res) {
		return res;
	}
	lowsyslog("Power stage OK\n");

	if (motor_test_motor()) {
		lowsyslog("Motor is not connected or damaged\n");
	} else {
		lowsyslog("Motor OK\n");
	}
	return 0;
}

__attribute__((noreturn))
void die(int status)
{
	uavcan_node::set_node_status_critical();
	::usleep(100000);
	lowsyslog("Init failed (%i)\n", status);
	// Really there is nothing left to do; just sit there and beep sadly:
	while (1) {
		motor_beep(100, 400);
		led_set_rgb(1, 0, 0);
		sleep(3);
	}
}

void do_startup_beep()
{
	motor_beep(1000, 100);
	::usleep(200 * 1000);
	motor_beep(1000, 100);
}

void print_banner()
{
	lowsyslog("\n\n\n");
	lowsyslog("\x1b\x5b\x48");      // Home sweet home
	lowsyslog("\x1b\x5b\x32\x4a");  // Clear
	lowsyslog("PX4ESC\n");
}

}

void application_halt_hook(void)
{
	motor_emergency();
	led_set_rgb(1, 0, 0);
}

int main()
{
	halInit();
	chSysInit();
	sdStart(&STDOUT_SD, NULL);

	usleep(300000);
	print_banner();

	const int init_status = init();

	console_init();

	if (init_status) {
		die(init_status);
	}

	do_startup_beep();

	motor_confirm_initialization();

	chThdSetPriority(LOWPRIO);

	uavcan_node::set_node_status_ok();

	/*
	 * Here we run some high-level self diagnostics
	 */
	while (1) {
		if (motor_is_blocked()) {
			uavcan_node::set_node_status_critical();
		} else {
			uavcan_node::set_node_status_ok();
		}
		::usleep(100 * 1000);
	}

	return 0;
}
<commit_msg>Minor changes in main<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2013 PX4 Development Team. All rights reserved.
 *   Author: Pavel Kirienko <pavel.kirienko@gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

#include <ch.h>
#include <hal.h>
#include <assert.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <config/config.h>
#include <sys.h>
#include <led.h>
#include <console.h>
#include <watchdog.h>
#include <motor/motor.h>
#include <uavcan_node/uavcan_node.hpp>

namespace
{

int init()
{
	int res = 0;

	/*
	 * Indication
	 */
	led_init();
	led_set_rgb(0.05, 0.05, 0.05);

	/*
	 * Config
	 */
	res = config_init();
	if (res) {
		return res;
	}

	/*
	 * Safety
	 */
	watchdog_init();

	/*
	 * UAVCAN node
	 */
	res = uavcan_node::init();
	if (res) {
		return res;
	}

	/*
	 * Motor control
	 */
	::usleep(10000);
	res = motor_init();
	if (res) {
		return res;
	}

	::usleep(10000);
	res = motor_test_hardware();
	if (res) {
		return res;
	}
	lowsyslog("Power stage OK\n");

	if (motor_test_motor()) {
		lowsyslog("Motor is not connected or damaged\n");
	} else {
		lowsyslog("Motor OK\n");
	}
	return 0;
}

__attribute__((noreturn))
void die(int status)
{
	::usleep(100000);
	lowsyslog("Init failed (%i)\n", status);
	// Really there is nothing left to do; just sit there and beep sadly:
	while (1) {
		motor_beep(100, 400);
		uavcan_node::set_node_status_critical();
		led_set_rgb(1, 0, 0);
		sleep(3);
	}
}

void do_startup_beep()
{
	motor_beep(1000, 100);
	::usleep(200 * 1000);
	motor_beep(1000, 100);
}

void print_banner()
{
	lowsyslog("\n\n\n");
	lowsyslog("\x1b\x5b\x48");      // Home sweet home
	lowsyslog("\x1b\x5b\x32\x4a");  // Clear
	lowsyslog("PX4ESC\n");
}

}

void application_halt_hook(void)
{
	motor_emergency();
	led_set_rgb(1, 0, 0);
}

int main()
{
	halInit();
	chSysInit();
	sdStart(&STDOUT_SD, NULL);

	usleep(300000);
	print_banner();

	const int init_status = init();

	console_init();

	if (init_status) {
		die(init_status);
	}

	do_startup_beep();

	motor_confirm_initialization();

	chThdSetPriority(LOWPRIO);

	uavcan_node::set_node_status_ok();

	/*
	 * Here we run some high-level self diagnostics
	 */
	while (1) {
		if (motor_is_blocked()) {
			uavcan_node::set_node_status_critical();
		} else {
			uavcan_node::set_node_status_ok();
		}
		::usleep(100 * 1000);
	}

	return 0;
}
<|endoftext|>


<commit_before><commit_msg>fix eigen2_bug_132 test<commit_after><|endoftext|>


<commit_before>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "avmplus.h"

#ifdef VMCFG_AOT

#include "AOTCompiler.h"

#ifdef DEBUGGER
#include "avmplusDebugger.h"
#endif

using namespace avmplus;

typedef Traits** LLVMTraitsId;
typedef Namespace** LLVMNamespaceId;

extern "C" {
    const AOTInfo aotInfos[] = {};
    const size_t nAOTInfos = 0;
    const AbcEnv* aotAbcEnvs[] = {};
    const uint32_t nAotAbcEnvs = 0;
    const AOTInfo builtin_aotInfo = EMPTY_AOTInfo;
    const AOTInfo shell_toplevel_aotInfo = EMPTY_AOTInfo;
    const AOTInfo avmglue_aotInfo = EMPTY_AOTInfo;
    const uint32_t abcNVectorInstances = 0;
    __attribute__ ((visibility("default"))) LLVMVectorInstance abcVectorInstances[] = {};
    LLVMUnusedParam const g_unusedParam = 0;
}

extern "C" __attribute__ ((visibility("default"))) const struct
{
    const char* n_Atom;
    LLVMAtom* m_Atom;

    const char* n_Boolean;
    LLVMBool* m_Boolean;

    const char* n_int;
    int32_t* m_int;

    const char* n_uint;
    uint32_t* m_uint;

    const char* n_MethodEnv;
    MethodEnv* m_MethodEnv;

    const char* n_AbcEnv;
    AbcEnv* m_AbcEnv;

    const char* n_Multiname;
    Multiname* m_Multiname;

    const char* n_Namespace;
    Namespace* m_Namespace;

    const char* n_NamespaceId;
    LLVMNamespaceId* m_NamespaceId;

    const char* n_Number;
    double* m_Number;

    const char* n_ScriptObject;
    ScriptObject* m_ScriptObject;

    const char* n_ArrayObject;
    ArrayObject* m_ArrayObject;

    const char* n_QNameObject;
    QNameObject* m_QNameObject;

    const char* n_String;
    String* m_String;

    const char* n_CompiledHandler;
    AvmThunkNativeFunctionHandler m_CompiledHandler;

    const char* n_ExceptionFrame;
    ExceptionFrame* m_ExceptionFrame;

    const char* n_CallStackNode;
    CallStackNode* m_CallStackNode;

    const char* n_Traits;
    Traits* m_traits;

    const char* n_TraitsId;
    LLVMTraitsId* m_traitsId;

    const char* n_aotInfo;
    AOTInfo* m_aotInfo;

    const char* n_LLVMUnusedParam;
    LLVMUnusedParam* m_UnusedParam;

    const char* n_MultinameIndex;
    LLVMMultinameIndex* m_MultinameIndex;

    const char* n_MultinameIndexMaybeInt;
    LLVMMultinameIndexMaybeInt* m_MultinameIndexMaybeInt;

    const char* n_LLVMMultinamePtrMaybeInt;
    LLVMMultinamePtrMaybeInt* m_LLVMMultinamePtrMaybeInt;

    const char* n_MethodDebugInfo;
    MethodDebugInfo* m_MethodDebugInfo;

    const char* n_char;
    char* m_char;

    const char *n_AOTMethodFrame;
    AOTMethodFrame *m_AOTMethodFrame;

    const char *n_AOTLazyEvalInfo;
    AOTLazyEvalInfo *m_AOTLazyEvalInfo;

    const char* n_AtomWB;
    AtomWB* m_AtomWB;

    const char* n_StringWB;
    MMgc::WriteBarrierRC<String*>* m_StringWB;

    const char* n_NamespaceWB;
    MMgc::WriteBarrierRC<Namespace*>* m_NamespaceWB;

    const char* n_ScriptObjectWB;
    MMgc::WriteBarrierRC<ScriptObject*>* m_ScriptObjectWB;

    const char* n_AOTActivationInfo;
    AOTActivationInfo* m_AOTActivationInfo;

    const char* n_DoubleVectorObject;
    DoubleVectorObject* m_DoubleVectorObject;

    const char* n_IntVectorObject;
    IntVectorObject* m_IntVectorObject;

    const char* n_UIntVectorObject;
    UIntVectorObject* m_UIntVectorObject;

    const char* n_ObjectVectorObject;
    ObjectVectorObject* m_ObjectVectorObject;

    const char* n_InterfaceBindingFunction;
    InterfaceBindingFunction m_InterfaceBindingFunction;

}  abcTypes =
{
    "Atom", 0,
    "Boolean", 0,
    "int", 0,
    "uint", 0,
    "MethodEnv", 0,
    "AbcEnv", 0,
    "Multiname", 0,
    "Namespace", 0,
    "NamespaceId", 0,
    "Number", 0,
    "ScriptObject", 0,
    "ArrayObject", 0,
    "QNameObject", 0,
    "String", 0,
    "CompiledHandler", 0,
    "ExceptionFrame", 0,
    "CallStackNode", 0,
    "Traits", 0,
    "TraitsId", 0,
    "AOTInfo", 0,
    "UnsedParam", 0,
    "MultinameIndex", 0,
    "MultinameIndexMaybeInt", 0,
    "MultinamePtrMaybeInt", 0,
    "MethodDebugInfo", 0,
    "char", 0,
    "AOTMethodFrame", 0,
    "AOTLazyEvalInfo", 0,
    "AtomWB", 0,
    "StringWB", 0,
    "NamespaceWB", 0,
    "ScriptObjectWB", 0,
    "AOTActivationInfo", 0,
    "DoubleVectorObject", 0,
    "IntVectorObject", 0,
    "UIntVectorObject", 0,
    "ObjectVectorObject", 0,
    "InterfaceBindingFunction", 0,
};

namespace avmplus
{
    // Stub out the interpreter
    uintptr_t interpGPR(MethodEnv* method, int /*argc*/, uint32_t */*ap*/)
    {
        method->toplevel()->throwVerifyError(kCorruptABCError);
        return 0;
    }

    double interpFPR(MethodEnv* method, int /*argc*/, uint32_t */*ap*/)
    {
        method->toplevel()->throwVerifyError(kCorruptABCError);
        return 0;
    }

    Atom interpBoxed(MethodEnv* method, int /*argc*/, Atom* /*ap*/)
    {
        method->toplevel()->throwVerifyError(kCorruptABCError);
        return 0;
    }
}

#ifdef VMCFG_BUFFER_GUARD
AOTLazyEvalGuard::AOTLazyEvalGuard(const avmplus::AbcEnv *abcEnv)
: LoadRedirGuard(abcEnv->pool()->aotInfo->nLazyEvals)
, m_abcEnv(abcEnv)
{
    PoolObject *pool = m_abcEnv->pool();
    if(pool->aotRoot == NULL) {
        const AOTInfo *info = pool->aotInfo;
        AvmAssert(info != NULL);
        pool->aotRoot = new MMgc::GCRoot(pool->core->gc, m_abcEnv->pool()->aotInfo->lazyEvalVals, m_abcEnv->pool()->aotInfo->nLazyEvals * sizeof(uintptr_t));
        for(uint32_t n = 0; n < info->nLazyEvals; n++)
            info->lazyEvalValPtrs[n] = getNextRedirPtr();
    } else {
        // Currently we require a one-one mapping of AbcEnv to
        // PoolObject. We should only reach this codepath when
        // constructing "empty" AbcEnvs used by media loading
        // operations. We set the abcEnv to NULL just to make it
        // clear that this guard object should never be used.
        m_abcEnv = NULL;
    }
}

uintptr_t *AOTLazyEvalGuard::redirectLoad(uintptr_t *faultAddr)
{
    AvmAssert(m_abcEnv != NULL);
    const AOTInfo *info = m_abcEnv->pool()->aotInfo;
    int lazyEvalNum = faultAddr - getFirstRedirPtr();
    uintptr_t *redir = info->lazyEvalVals + lazyEvalNum;
    // next time, get the right value
    if(info->lazyEvalValPtrs[lazyEvalNum] != redir)
    {
        // printf("fixing %p to %p...\n", faultAddr, redir);
        const AOTLazyEvalInfo &evalInfo = info->lazyEvalInfos[lazyEvalNum];
        avmplus::MethodEnv *env = m_abcEnv->getMethod(evalInfo.methodID);
        // fprintf(stderr, "methodId: %d leNum: %d (%p) %p\n", evalInfo.methodID, lazyEvalNum, faultAddr, env);
        AvmAssert(env != 0);
        *redir = evalInfo.func(env, evalInfo.funcData);
        // set this after computation in case of recursion
        info->lazyEvalValPtrs[lazyEvalNum] = redir;
        // printf("fixed %p to %p...\n", faultAddr, redir);
    }
    return redir;
}
#endif

// UGLY Hack to avoid the pthread_setspecific overhead with exceptions in ARM-GCC-4.0.1
// TODO: remove this once we have a good way of disabling exceptions
extern "C" {
    void _Unwind_SjLj_Register() {
    }

    void _Unwind_SjLj_Resume() {
    }

    void _Unwind_SjLj_Unregister() {
    }
}

extern "C" void llvm_unwind() {
    // This implementation gets replaced by one generated
    // by the LLVM Emitter. It exists simply to make it
    // possible to complete a full compile and link of
    // avmshell with no compiled code.

    printf("Error: this should never be called.\n");
    AvmAssert(false);
}

#endif //VMCFG_AOT
<commit_msg>AOT fix: force instantiation of WB template classes to avoid AOT-specific compile errors (r=stejohns,alexmac)<commit_after>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "avmplus.h"

#ifdef VMCFG_AOT

#include "AOTCompiler.h"

#ifdef DEBUGGER
#include "avmplusDebugger.h"
#endif

using namespace avmplus;

typedef Traits** LLVMTraitsId;
typedef Namespace** LLVMNamespaceId;

// force instantiation in case the headers haven't already
template class MMgc::WriteBarrierRC<avmplus::String*>;
template class MMgc::WriteBarrierRC<avmplus::Namespace*>;
template class MMgc::WriteBarrierRC<avmplus::ScriptObject*>;

extern "C" {
    const AOTInfo aotInfos[] = {};
    const size_t nAOTInfos = 0;
    const AbcEnv* aotAbcEnvs[] = {};
    const uint32_t nAotAbcEnvs = 0;
    const AOTInfo builtin_aotInfo = EMPTY_AOTInfo;
    const AOTInfo shell_toplevel_aotInfo = EMPTY_AOTInfo;
    const AOTInfo avmglue_aotInfo = EMPTY_AOTInfo;
    const uint32_t abcNVectorInstances = 0;
    __attribute__ ((visibility("default"))) LLVMVectorInstance abcVectorInstances[] = {};
    LLVMUnusedParam const g_unusedParam = 0;
}

extern "C" __attribute__ ((visibility("default"))) const struct
{
    const char* n_Atom;
    LLVMAtom* m_Atom;

    const char* n_Boolean;
    LLVMBool* m_Boolean;

    const char* n_int;
    int32_t* m_int;

    const char* n_uint;
    uint32_t* m_uint;

    const char* n_MethodEnv;
    MethodEnv* m_MethodEnv;

    const char* n_AbcEnv;
    AbcEnv* m_AbcEnv;

    const char* n_Multiname;
    Multiname* m_Multiname;

    const char* n_Namespace;
    Namespace* m_Namespace;

    const char* n_NamespaceId;
    LLVMNamespaceId* m_NamespaceId;

    const char* n_Number;
    double* m_Number;

    const char* n_ScriptObject;
    ScriptObject* m_ScriptObject;

    const char* n_ArrayObject;
    ArrayObject* m_ArrayObject;

    const char* n_QNameObject;
    QNameObject* m_QNameObject;

    const char* n_String;
    String* m_String;

    const char* n_CompiledHandler;
    AvmThunkNativeFunctionHandler m_CompiledHandler;

    const char* n_ExceptionFrame;
    ExceptionFrame* m_ExceptionFrame;

    const char* n_CallStackNode;
    CallStackNode* m_CallStackNode;

    const char* n_Traits;
    Traits* m_traits;

    const char* n_TraitsId;
    LLVMTraitsId* m_traitsId;

    const char* n_aotInfo;
    AOTInfo* m_aotInfo;

    const char* n_LLVMUnusedParam;
    LLVMUnusedParam* m_UnusedParam;

    const char* n_MultinameIndex;
    LLVMMultinameIndex* m_MultinameIndex;

    const char* n_MultinameIndexMaybeInt;
    LLVMMultinameIndexMaybeInt* m_MultinameIndexMaybeInt;

    const char* n_LLVMMultinamePtrMaybeInt;
    LLVMMultinamePtrMaybeInt* m_LLVMMultinamePtrMaybeInt;

    const char* n_MethodDebugInfo;
    MethodDebugInfo* m_MethodDebugInfo;

    const char* n_char;
    char* m_char;

    const char *n_AOTMethodFrame;
    AOTMethodFrame *m_AOTMethodFrame;

    const char *n_AOTLazyEvalInfo;
    AOTLazyEvalInfo *m_AOTLazyEvalInfo;

    const char* n_AtomWB;
    AtomWB* m_AtomWB;

    const char* n_StringWB;
    MMgc::WriteBarrierRC<String*>* m_StringWB;

    const char* n_NamespaceWB;
    MMgc::WriteBarrierRC<Namespace*>* m_NamespaceWB;

    const char* n_ScriptObjectWB;
    MMgc::WriteBarrierRC<ScriptObject*>* m_ScriptObjectWB;

    const char* n_AOTActivationInfo;
    AOTActivationInfo* m_AOTActivationInfo;

    const char* n_DoubleVectorObject;
    DoubleVectorObject* m_DoubleVectorObject;

    const char* n_IntVectorObject;
    IntVectorObject* m_IntVectorObject;

    const char* n_UIntVectorObject;
    UIntVectorObject* m_UIntVectorObject;

    const char* n_ObjectVectorObject;
    ObjectVectorObject* m_ObjectVectorObject;

    const char* n_InterfaceBindingFunction;
    InterfaceBindingFunction m_InterfaceBindingFunction;

}  abcTypes =
{
    "Atom", 0,
    "Boolean", 0,
    "int", 0,
    "uint", 0,
    "MethodEnv", 0,
    "AbcEnv", 0,
    "Multiname", 0,
    "Namespace", 0,
    "NamespaceId", 0,
    "Number", 0,
    "ScriptObject", 0,
    "ArrayObject", 0,
    "QNameObject", 0,
    "String", 0,
    "CompiledHandler", 0,
    "ExceptionFrame", 0,
    "CallStackNode", 0,
    "Traits", 0,
    "TraitsId", 0,
    "AOTInfo", 0,
    "UnsedParam", 0,
    "MultinameIndex", 0,
    "MultinameIndexMaybeInt", 0,
    "MultinamePtrMaybeInt", 0,
    "MethodDebugInfo", 0,
    "char", 0,
    "AOTMethodFrame", 0,
    "AOTLazyEvalInfo", 0,
    "AtomWB", 0,
    "StringWB", 0,
    "NamespaceWB", 0,
    "ScriptObjectWB", 0,
    "AOTActivationInfo", 0,
    "DoubleVectorObject", 0,
    "IntVectorObject", 0,
    "UIntVectorObject", 0,
    "ObjectVectorObject", 0,
    "InterfaceBindingFunction", 0,
};

namespace avmplus
{
    // Stub out the interpreter
    uintptr_t interpGPR(MethodEnv* method, int /*argc*/, uint32_t */*ap*/)
    {
        method->toplevel()->throwVerifyError(kCorruptABCError);
        return 0;
    }

    double interpFPR(MethodEnv* method, int /*argc*/, uint32_t */*ap*/)
    {
        method->toplevel()->throwVerifyError(kCorruptABCError);
        return 0;
    }

    Atom interpBoxed(MethodEnv* method, int /*argc*/, Atom* /*ap*/)
    {
        method->toplevel()->throwVerifyError(kCorruptABCError);
        return 0;
    }
}

#ifdef VMCFG_BUFFER_GUARD
AOTLazyEvalGuard::AOTLazyEvalGuard(const avmplus::AbcEnv *abcEnv)
: LoadRedirGuard(abcEnv->pool()->aotInfo->nLazyEvals)
, m_abcEnv(abcEnv)
{
    PoolObject *pool = m_abcEnv->pool();
    if(pool->aotRoot == NULL) {
        const AOTInfo *info = pool->aotInfo;
        AvmAssert(info != NULL);
        pool->aotRoot = new MMgc::GCRoot(pool->core->gc, m_abcEnv->pool()->aotInfo->lazyEvalVals, m_abcEnv->pool()->aotInfo->nLazyEvals * sizeof(uintptr_t));
        for(uint32_t n = 0; n < info->nLazyEvals; n++)
            info->lazyEvalValPtrs[n] = getNextRedirPtr();
    } else {
        // Currently we require a one-one mapping of AbcEnv to
        // PoolObject. We should only reach this codepath when
        // constructing "empty" AbcEnvs used by media loading
        // operations. We set the abcEnv to NULL just to make it
        // clear that this guard object should never be used.
        m_abcEnv = NULL;
    }
}

uintptr_t *AOTLazyEvalGuard::redirectLoad(uintptr_t *faultAddr)
{
    AvmAssert(m_abcEnv != NULL);
    const AOTInfo *info = m_abcEnv->pool()->aotInfo;
    int lazyEvalNum = faultAddr - getFirstRedirPtr();
    uintptr_t *redir = info->lazyEvalVals + lazyEvalNum;
    // next time, get the right value
    if(info->lazyEvalValPtrs[lazyEvalNum] != redir)
    {
        // printf("fixing %p to %p...\n", faultAddr, redir);
        const AOTLazyEvalInfo &evalInfo = info->lazyEvalInfos[lazyEvalNum];
        avmplus::MethodEnv *env = m_abcEnv->getMethod(evalInfo.methodID);
        // fprintf(stderr, "methodId: %d leNum: %d (%p) %p\n", evalInfo.methodID, lazyEvalNum, faultAddr, env);
        AvmAssert(env != 0);
        *redir = evalInfo.func(env, evalInfo.funcData);
        // set this after computation in case of recursion
        info->lazyEvalValPtrs[lazyEvalNum] = redir;
        // printf("fixed %p to %p...\n", faultAddr, redir);
    }
    return redir;
}
#endif

// UGLY Hack to avoid the pthread_setspecific overhead with exceptions in ARM-GCC-4.0.1
// TODO: remove this once we have a good way of disabling exceptions
extern "C" {
    void _Unwind_SjLj_Register() {
    }

    void _Unwind_SjLj_Resume() {
    }

    void _Unwind_SjLj_Unregister() {
    }
}

extern "C" void llvm_unwind() {
    // This implementation gets replaced by one generated
    // by the LLVM Emitter. It exists simply to make it
    // possible to complete a full compile and link of
    // avmshell with no compiled code.

    printf("Error: this should never be called.\n");
    AvmAssert(false);
}

#endif //VMCFG_AOT
<|endoftext|>


<commit_before>/*
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */

#include "../kroll.h"
#include <sstream>

namespace kroll
{

	ArgList::ArgList()
	{
		this->args = new std::vector<SharedValue>;
	}

	ArgList::ArgList(SharedValue a)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
	}

	ArgList::ArgList(SharedValue a, SharedValue b)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
		this->args->push_back(b);
	}

	ArgList::ArgList(SharedValue a, SharedValue b, SharedValue c)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
		this->args->push_back(b);
		this->args->push_back(c);
	}

	ArgList::ArgList(SharedValue a, SharedValue b, SharedValue c, SharedValue d)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
		this->args->push_back(b);
		this->args->push_back(c);
		this->args->push_back(d);
	}

	ArgList::ArgList(const ArgList& other)
	{
		this->args = other.args;
	}

	void ArgList::push_back(SharedValue v)
	{
		this->args->push_back(v);
	}

	size_t ArgList::size() const
	{
		return this->args->size();
	}

	const SharedValue& ArgList::at(size_t index) const
	{
		return this->args->at(index);
	}

	const SharedValue& ArgList::operator[](size_t index) const
	{
		return this->args->at(index);
	}

	bool ArgList::Verify(const char* sig) const
	{
		std::vector<std::string>* sig_vector = ArgList::ParseSigString(sig);
		return ArgList::VerifyImpl(sig_vector);
	}

	void ArgList::VerifyException(const char *name, const char* sig) const
	{
		std::vector<std::string>* sig_vector = ArgList::ParseSigString(sig);
		if (!VerifyImpl(sig_vector))
		{
			SharedString sig = ArgList::GenerateSignature(name, sig_vector);
			std::string s = "Invalid arguments passed for: " + *sig;
			delete sig_vector;
			throw ValueException::FromString(s);
		}
		delete sig_vector;
	}

	inline std::vector<std::string>* ArgList::ParseSigString(const char* sig)
	{
		std::vector<std::string>* sig_vector = new std::vector<std::string>();
		std::string types = "";
		while (true)
		{
			if (*sig == '\0')
			{
				break;
			}
			else if (*sig == ',' || *sig == ' ')
			{
				sig_vector->push_back(types);
				types = "";
			}
			else
			{
				types += *sig;
			}
			*sig++;
		}
		return sig_vector;
	}

	SharedString ArgList::GenerateSignature(const char* name, std::vector<std::string>* sig_vector)
	{
		std::ostringstream out;
		out << name << "(";
		bool optional = false;
		for (size_t i = 0; i < sig_vector->size(); i++)
		{
			const char *t = sig_vector->at(i).c_str();
			// The first time we see the optional
			// parameter we stay in optional mode
			// until the end of the session.
			if (*t== '?')
			{
				optional = true;
				out << "[";
				*t++;
			}

			while (*t != '\0')
			{
				if (*t == 's')
					out << "String";
				if (*t == 'b')
					out << "Boolean";
				else if (*t == 'i')
					out << "Integer";
				else if (*t == 'd')
					out << "Double";
				else if (*t == 'n')
					out << "Number";
				else if (*t == 'o')
					out << "Object";
				else if (*t == 'l')
					out << "List";
				else if (*t == 'm')
					out << "Function";
				else if (*t == '0')
					out << "Null";
				*t++;
				if (*t != '\0')
					out << "|";
			}

			if (i != sig_vector->size() - 1)
				out << ",";
		}

		if (optional)
		{
			out << "]";
		}

		out << ")";
		return new std::string(out.str());
	}

	bool ArgList::VerifyImpl(std::vector<std::string>* sig_vector) const
	{
		bool optional = false;
		for (size_t i = 0; i < sig_vector->size(); i++)
		{
			const char *t = sig_vector->at(i).c_str();

			// The first time we see the optional
			// parameter we stay in optional mode
			// until the end of the session.
			if (*t == '?')
			{
				optional = true;
				*t++;
			}

			// Not enough args given, but we're in
			// optional mode.
			if (this->size() < i + 1 && optional)
				return true;

			// Not enough args given.
			if (this->size() < i + 1)
				return false;

			// Arg doesn't conform to arg string
			if (!ArgList::VerifyArg(this->at(i), t))
				return false;
		}
		return true;
	}

	inline bool ArgList::VerifyArg(SharedValue arg, const char* t)
	{
		while (*t != '\0')
		{
		// Check if type of value matches current character.
		if ((*t == 's' && arg->IsString())
		 || (*t == 'b' && arg->IsBool())
		 || (*t == 'i' && arg->IsInt())
		 || (*t == 'd' && arg->IsDouble())
		 || (*t == 'n' && arg->IsNumber())
		 || (*t == 'o' && arg->IsObject())
		 || (*t == 'l' && arg->IsList())
		 || (*t == 'm' && arg->IsMethod())
		 || (*t == '0' && arg->IsNull()))
			return true;
		else
			*t++;
		}
		return false;
	}

	int ArgList::GetInt(size_t index, int defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsInt())
		{
			return this->at(index)->ToInt();
		}
		else
		{
			return defaultValue;
		}
	}

	double ArgList::GetDouble(size_t index, double defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsDouble())
		{
			return this->at(index)->ToDouble();
		}
		else
		{
			return defaultValue;
		}
	}

	double ArgList::GetNumber(size_t index, double defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsNumber())
		{
			return this->at(index)->ToDouble();
		}
		else
		{
			return defaultValue;
		}
	}

	bool ArgList::GetBool(size_t index, bool defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsBool())
		{
			return this->at(index)->ToBool();
		}
		else
		{
			return defaultValue;
		}
	}

	std::string ArgList::GetString(size_t index, std::string defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsString())
		{
			return this->at(index)->ToString();
		}
		else
		{
			return defaultValue;
		}
	}

	SharedKObject ArgList::GetObject(size_t index, SharedKObject defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsObject())
		{
			return this->at(index)->ToObject();
		}
		else
		{
			return defaultValue;
		}
	}

	SharedKMethod ArgList::GetMethod(size_t index, SharedKMethod defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsMethod())
		{
			return this->at(index)->ToMethod();
		}
		else
		{
			return defaultValue;
		}
	}

	SharedKList ArgList::GetList(size_t index, SharedKList defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsList())
		{
			return this->at(index)->ToList();
		}
		else
		{
			return defaultValue;
		}
	}
}

<commit_msg>ArgList: Add the last argument to the signature vector<commit_after>/*
 * Appcelerator Kroll - licensed under the Apache Public License 2
 * see LICENSE in the root folder for details on the license.
 * Copyright (c) 2008 Appcelerator, Inc. All Rights Reserved.
 */

#include "../kroll.h"
#include <sstream>

namespace kroll
{

	ArgList::ArgList()
	{
		this->args = new std::vector<SharedValue>;
	}

	ArgList::ArgList(SharedValue a)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
	}

	ArgList::ArgList(SharedValue a, SharedValue b)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
		this->args->push_back(b);
	}

	ArgList::ArgList(SharedValue a, SharedValue b, SharedValue c)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
		this->args->push_back(b);
		this->args->push_back(c);
	}

	ArgList::ArgList(SharedValue a, SharedValue b, SharedValue c, SharedValue d)
	{
		this->args = new std::vector<SharedValue>;
		this->args->push_back(a);
		this->args->push_back(b);
		this->args->push_back(c);
		this->args->push_back(d);
	}

	ArgList::ArgList(const ArgList& other)
	{
		this->args = other.args;
	}

	void ArgList::push_back(SharedValue v)
	{
		this->args->push_back(v);
	}

	size_t ArgList::size() const
	{
		return this->args->size();
	}

	const SharedValue& ArgList::at(size_t index) const
	{
		return this->args->at(index);
	}

	const SharedValue& ArgList::operator[](size_t index) const
	{
		return this->args->at(index);
	}

	bool ArgList::Verify(const char* sig) const
	{
		std::vector<std::string>* sig_vector = ArgList::ParseSigString(sig);
		return ArgList::VerifyImpl(sig_vector);
	}

	void ArgList::VerifyException(const char *name, const char* sig) const
	{
		std::vector<std::string>* sig_vector = ArgList::ParseSigString(sig);
		if (!VerifyImpl(sig_vector))
		{
			SharedString sig = ArgList::GenerateSignature(name, sig_vector);
			std::string s = "Invalid arguments passed for: " + *sig;
			delete sig_vector;
			throw ValueException::FromString(s);
		}
		delete sig_vector;
	}

	inline std::vector<std::string>* ArgList::ParseSigString(const char* sig)
	{
		std::vector<std::string>* sig_vector = new std::vector<std::string>();
		std::string types = "";
		while (true)
		{
			if (*sig == '\0')
			{
				break;
			}
			else if (*sig == ',' || *sig == ' ')
			{
				sig_vector->push_back(types);
				types = "";
			}
			else
			{
				types += *sig;
			}
			*sig++;
		}

		if (!types.empty())
			sig_vector->push_back(types);
		return sig_vector;
	}

	SharedString ArgList::GenerateSignature(const char* name, std::vector<std::string>* sig_vector)
	{
		std::ostringstream out;
		out << name << "(";
		bool optional = false;
		for (size_t i = 0; i < sig_vector->size(); i++)
		{
			const char *t = sig_vector->at(i).c_str();
			// The first time we see the optional
			// parameter we stay in optional mode
			// until the end of the session.
			if (*t== '?')
			{
				optional = true;
				out << "[";
				*t++;
			}

			while (*t != '\0')
			{
				if (*t == 's')
					out << "String";
				if (*t == 'b')
					out << "Boolean";
				else if (*t == 'i')
					out << "Integer";
				else if (*t == 'd')
					out << "Double";
				else if (*t == 'n')
					out << "Number";
				else if (*t == 'o')
					out << "Object";
				else if (*t == 'l')
					out << "List";
				else if (*t == 'm')
					out << "Function";
				else if (*t == '0')
					out << "Null";
				*t++;
				if (*t != '\0')
					out << "|";
			}

			if (i != sig_vector->size() - 1)
				out << ",";
		}

		if (optional)
		{
			out << "]";
		}

		out << ")";
		return new std::string(out.str());
	}

	bool ArgList::VerifyImpl(std::vector<std::string>* sig_vector) const
	{
		bool optional = false;
		for (size_t i = 0; i < sig_vector->size(); i++)
		{
			const char *t = sig_vector->at(i).c_str();

			// The first time we see the optional
			// parameter we stay in optional mode
			// until the end of the session.
			if (*t == '?')
			{
				optional = true;
				*t++;
			}

			// Not enough args given, but we're in
			// optional mode.
			if (this->size() < i + 1 && optional)
			{
				return true;
			}

			// Not enough args given.
			if (this->size() < i + 1)
			{
				return false;
			}

			// Arg doesn't conform to arg string
			if (!ArgList::VerifyArg(this->at(i), t))
			{
				return false;
			}
		}
		return true;
	}

	inline bool ArgList::VerifyArg(SharedValue arg, const char* t)
	{
		while (*t != '\0')
		{
		// Check if type of value matches current character.
		if ((*t == 's' && arg->IsString())
		 || (*t == 'b' && arg->IsBool())
		 || (*t == 'i' && arg->IsInt())
		 || (*t == 'd' && arg->IsDouble())
		 || (*t == 'n' && arg->IsNumber())
		 || (*t == 'o' && arg->IsObject())
		 || (*t == 'l' && arg->IsList())
		 || (*t == 'm' && arg->IsMethod())
		 || (*t == '0' && arg->IsNull()))
			return true;
		else
			*t++;
		}
		return false;
	}

	int ArgList::GetInt(size_t index, int defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsInt())
		{
			return this->at(index)->ToInt();
		}
		else
		{
			return defaultValue;
		}
	}

	double ArgList::GetDouble(size_t index, double defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsDouble())
		{
			return this->at(index)->ToDouble();
		}
		else
		{
			return defaultValue;
		}
	}

	double ArgList::GetNumber(size_t index, double defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsNumber())
		{
			return this->at(index)->ToDouble();
		}
		else
		{
			return defaultValue;
		}
	}

	bool ArgList::GetBool(size_t index, bool defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsBool())
		{
			return this->at(index)->ToBool();
		}
		else
		{
			return defaultValue;
		}
	}

	std::string ArgList::GetString(size_t index, std::string defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsString())
		{
			return this->at(index)->ToString();
		}
		else
		{
			return defaultValue;
		}
	}

	SharedKObject ArgList::GetObject(size_t index, SharedKObject defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsObject())
		{
			return this->at(index)->ToObject();
		}
		else
		{
			return defaultValue;
		}
	}

	SharedKMethod ArgList::GetMethod(size_t index, SharedKMethod defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsMethod())
		{
			return this->at(index)->ToMethod();
		}
		else
		{
			return defaultValue;
		}
	}

	SharedKList ArgList::GetList(size_t index, SharedKList defaultValue) const
	{
		if (this->size() > index && this->at(index)->IsList())
		{
			return this->at(index)->ToList();
		}
		else
		{
			return defaultValue;
		}
	}
}

<|endoftext|>


<commit_before>
#define BOOST_TEST_MODULE heimdallr_client
#define WAIT_TIME 200
#define PROVIDER_ONE_UUID "1f383dc1-7eae-4e9a-9408-4a345204b372"

#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

#include "heimdallr_client.h"

using namespace std;

void sleepMS(unsigned time) {
    boost::this_thread::sleep(boost::posix_time::millisec(time));
}

class TestProvider : public hmdlr::Provider {
public:
    TestProvider(string token) : hmdlr::Provider(token) {
        url_ = "http://hmdlr.co";
        auth_source_ = "testing";
    }
    vector<hmdlr::delayed_message> getDelayedMessages() {
        return delayed_messages_;
    }
};

class TestConsumer : public hmdlr::Consumer {
public:
    TestConsumer(string token) : hmdlr::Consumer(token) {
        url_ = "http://hmdlr.co";
        auth_source_ = "testing";
    }
    vector<hmdlr::delayed_message> getDelayedMessages() {
        return delayed_messages_;
    }
};

struct ClientFixture {
    ClientFixture() {
        obj_msg = sio::object_message::create();
        obj_msg->get_map()["stringField"] = sio::string_message::create("");
        obj_msg->get_map()["arrayField"] = sio::array_message::create();
        obj_msg->get_map()["numberField"] = sio::double_message::create(0.0);

        str_msg = sio::string_message::create("");
    }
    sio::message::ptr obj_msg;
    sio::message::ptr str_msg;
};

struct ClientPairFixture : ClientFixture {
    ClientPairFixture() : ClientPairFixture("schema-uuid", "schema-uuid", true) {}
    ClientPairFixture(string provider_token, string consumer_token, bool connect) :
        ClientFixture(),
        provider(provider_token),
        consumer(consumer_token)
    {
        provider.on("hmdlr-error", [&](sio::event& ev) {
            provider_error = true;
            printf(
                "PROVIDER ERROR: %s\n",
                ev.get_message()->get_map()["message"]->get_string().c_str()
            );
        });
        provider.on("control", [&](sio::event& ev) {
            control_count++;
        });

        consumer.on("hmdlr-error", [&](sio::event& ev) {
            consumer_error = true;
            printf(
                "CONSUMER ERROR: %s\n",
                ev.get_message()->get_map()["message"]->get_string().c_str()
            );
        });
        consumer.on("event", [&](sio::event& ev) {
            event_count++;
        });
        consumer.on("sensor", [&](sio::event& ev) {
            sensor_count++;
        });

        if (connect) {
            provider.connect();
            consumer.connect();
        }

    }
    ~ClientPairFixture() {
        sleepMS(WAIT_TIME);
        BOOST_REQUIRE_MESSAGE(!provider_error, "Provider received an error");
        BOOST_REQUIRE_MESSAGE(!consumer_error, "Consumer received an error");
    }

    TestProvider provider;
    TestConsumer consumer;
    bool provider_error = false;
    bool consumer_error = false;
    int event_count = 0;
    int sensor_count = 0;
    int control_count = 0;
};

BOOST_AUTO_TEST_SUITE( provider )
BOOST_AUTO_TEST_CASE( receives_hmdlr_error ) {
    ClientPairFixture f("invalid-uuid", "N/A", false);

    f.provider.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(f.provider_error);

    f.provider_error = false;
}

BOOST_AUTO_TEST_CASE( removes_listener ) {
    ClientPairFixture f("invalid-uuid", "N/A", false);

    f.provider.removeListener("hmdlr-error");
    f.provider.connect();
}

BOOST_AUTO_TEST_CASE( authorizes ) {
    ClientPairFixture f("valid-uuid", "N/A", false);
    bool authorized = false;

    f.provider.on("auth-success", [&](sio::event& ev) {
        authorized = true;
    });
    f.provider.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(authorized);
}

BOOST_AUTO_TEST_CASE( waits_until_ready ) {
    ClientPairFixture f("schema-uuid", "N/A", false);
    vector<hmdlr::delayed_message> msg_vector;
    sio::message::ptr data;

    f.provider.sendEvent("objectTest", f.obj_msg);
    f.provider.sendSensor("stringTest", f.str_msg);
    msg_vector = f.provider.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 2,
        "size before connect: " << msg_vector.size()
    );

    data = msg_vector[0].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.obj_msg->get_flag() == data->get_flag(),
        "msg_vector[0] flag was: " << data->get_flag()
    );

    data = msg_vector[1].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.str_msg->get_flag() == data->get_flag(),
        "msg_vector[1] flag was: " << data->get_flag()
    );

    f.provider.connect();
    sleepMS(WAIT_TIME);
    msg_vector = f.provider.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 0,
        "size after connect: " << msg_vector.size()
    );
}

BOOST_FIXTURE_TEST_CASE( completes_persistent, ClientPairFixture ) {
    provider.completed("test");
}

BOOST_FIXTURE_TEST_CASE( sends_packets, ClientPairFixture ) {
    provider.sendEvent("objectTest", obj_msg);
    provider.sendSensor("objectTest", obj_msg);
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( consumer )
BOOST_AUTO_TEST_CASE( receives_hmdlr_error ) {
    ClientPairFixture f("N/A", "invalid-uuid", false);

    f.consumer.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(f.consumer_error);

    f.consumer_error = false;
}

BOOST_AUTO_TEST_CASE( removes_listener ) {
    ClientPairFixture f("N/A", "invalid-uuid", false);

    f.consumer.removeListener("hmdlr-error");
    f.consumer.connect();
}

BOOST_AUTO_TEST_CASE( authorizes ) {
    ClientPairFixture f("N/A", "valid-uuid", false);
    bool authorized = false;

    f.consumer.on("auth-success", [&](sio::event& ev) {
        authorized = true;
    });
    f.consumer.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(authorized);
}

BOOST_AUTO_TEST_CASE( waits_until_ready ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", false);
    vector<hmdlr::delayed_message> msg_vector;
    sio::message::ptr data;

    f.consumer.sendControl(PROVIDER_ONE_UUID, "objectTest", f.obj_msg);
    f.consumer.sendControl(PROVIDER_ONE_UUID, "stringTest", f.str_msg);
    msg_vector = f.consumer.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 2,
        "size before connect: " << msg_vector.size()
    );

    data = msg_vector[0].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.obj_msg->get_flag() == data->get_flag(),
        "msg_vector[0] flag was: " << data->get_flag()
    );

    data = msg_vector[1].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.str_msg->get_flag() == data->get_flag(),
        "msg_vector[1] flag was: " << data->get_flag()
    );

    f.consumer.connect();
    f.provider.connect();
    sleepMS(WAIT_TIME);
    msg_vector = f.consumer.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 0,
        "size after connect: " << msg_vector.size()
    );
}

BOOST_AUTO_TEST_CASE( sends_control ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", true);

    f.consumer.sendControl(PROVIDER_ONE_UUID, "objectTest", f.obj_msg);
}

BOOST_FIXTURE_TEST_CASE( sets_filter, ClientPairFixture ) {
    sio::message::ptr filter = sio::object_message::create();

    filter->get_map()["event"] = sio::array_message::create();
    filter->get_map()["sensor"] = sio::array_message::create();

    consumer.setFilter(PROVIDER_ONE_UUID, filter);
}

BOOST_AUTO_TEST_CASE( gets_state ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", true);

    f.provider.sendEvent("objectTest", f.obj_msg);
    f.provider.sendEvent("stringTest", f.str_msg);
    sleepMS(WAIT_TIME);

    sio::message::ptr subtypes = sio::array_message::create();
    subtypes->get_vector().push_back(sio::string_message::create("objectTest"));
    subtypes->get_vector().push_back(sio::string_message::create("stringTest"));

    // schema is the UUID
    f.consumer.getState(PROVIDER_ONE_UUID, subtypes);

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE_MESSAGE(f.event_count == 2, "event_count was: " << f.event_count);
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( client_pair )
BOOST_AUTO_TEST_CASE ( interaction ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", true);

    f.consumer.subscribe(PROVIDER_ONE_UUID);
    f.provider.sendEvent("stringTest", f.str_msg);
    f.provider.sendSensor("objectTest", f.obj_msg);
    f.consumer.sendControl(PROVIDER_ONE_UUID, "objectTest", f.obj_msg);

    sleepMS(WAIT_TIME );
    BOOST_REQUIRE_MESSAGE(
        f.event_count == 1,
        "event_count was: " << f.event_count
    );
    BOOST_REQUIRE_MESSAGE(
        f.sensor_count == 1,
        "sensor_count was: " << f.sensor_count
    );
    BOOST_REQUIRE_MESSAGE(
        f.control_count == 1,
        "control_count was: " << f.control_count
    );
}
BOOST_AUTO_TEST_SUITE_END()<commit_msg>Was counting conect events as well<commit_after>
#define BOOST_TEST_MODULE heimdallr_client
#define WAIT_TIME 200
#define PROVIDER_ONE_UUID "1f383dc1-7eae-4e9a-9408-4a345204b372"

#include <boost/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <iostream>

#include "heimdallr_client.h"

using namespace std;

void sleepMS(unsigned time) {
    boost::this_thread::sleep(boost::posix_time::millisec(time));
}

class TestProvider : public hmdlr::Provider {
public:
    TestProvider(string token) : hmdlr::Provider(token) {
        url_ = "http://hmdlr.co";
        auth_source_ = "testing";
    }
    vector<hmdlr::delayed_message> getDelayedMessages() {
        return delayed_messages_;
    }
};

class TestConsumer : public hmdlr::Consumer {
public:
    TestConsumer(string token) : hmdlr::Consumer(token) {
        url_ = "http://hmdlr.co";
        auth_source_ = "testing";
    }
    vector<hmdlr::delayed_message> getDelayedMessages() {
        return delayed_messages_;
    }
};

struct ClientFixture {
    ClientFixture() {
        obj_msg = sio::object_message::create();
        obj_msg->get_map()["stringField"] = sio::string_message::create("");
        obj_msg->get_map()["arrayField"] = sio::array_message::create();
        obj_msg->get_map()["numberField"] = sio::double_message::create(0.0);

        str_msg = sio::string_message::create("");
    }
    sio::message::ptr obj_msg;
    sio::message::ptr str_msg;
};

struct ClientPairFixture : ClientFixture {
    ClientPairFixture() : ClientPairFixture("schema-uuid", "schema-uuid", true) {}
    ClientPairFixture(string provider_token, string consumer_token, bool connect) :
        ClientFixture(),
        provider(provider_token),
        consumer(consumer_token)
    {
        provider.on("hmdlr-error", [&](sio::event& ev) {
            provider_error = true;
            printf(
                "PROVIDER ERROR: %s\n",
                ev.get_message()->get_map()["message"]->get_string().c_str()
            );
        });
        provider.on("control", [&](sio::event& ev) {
            control_count++;
        });

        consumer.on("hmdlr-error", [&](sio::event& ev) {
            consumer_error = true;
            printf(
                "CONSUMER ERROR: %s\n",
                ev.get_message()->get_map()["message"]->get_string().c_str()
            );
        });
        consumer.on("event", [&](sio::event& ev) {
            if (ev.get_message()->get_map()["subtype"]->get_string() != "connected") {
                event_count++;
            }
        });
        consumer.on("sensor", [&](sio::event& ev) {
            sensor_count++;
        });

        if (connect) {
            provider.connect();
            consumer.connect();
        }

    }
    ~ClientPairFixture() {
        sleepMS(WAIT_TIME);
        BOOST_REQUIRE_MESSAGE(!provider_error, "Provider received an error");
        BOOST_REQUIRE_MESSAGE(!consumer_error, "Consumer received an error");
    }

    TestProvider provider;
    TestConsumer consumer;
    bool provider_error = false;
    bool consumer_error = false;
    int event_count = 0;
    int sensor_count = 0;
    int control_count = 0;
};

BOOST_AUTO_TEST_SUITE( provider )
BOOST_AUTO_TEST_CASE( receives_hmdlr_error ) {
    ClientPairFixture f("invalid-uuid", "N/A", false);

    f.provider.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(f.provider_error);

    f.provider_error = false;
}

BOOST_AUTO_TEST_CASE( removes_listener ) {
    ClientPairFixture f("invalid-uuid", "N/A", false);

    f.provider.removeListener("hmdlr-error");
    f.provider.connect();
}

BOOST_AUTO_TEST_CASE( authorizes ) {
    ClientPairFixture f("valid-uuid", "N/A", false);
    bool authorized = false;

    f.provider.on("auth-success", [&](sio::event& ev) {
        authorized = true;
    });
    f.provider.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(authorized);
}

BOOST_AUTO_TEST_CASE( waits_until_ready ) {
    ClientPairFixture f("schema-uuid", "N/A", false);
    vector<hmdlr::delayed_message> msg_vector;
    sio::message::ptr data;

    f.provider.sendEvent("objectTest", f.obj_msg);
    f.provider.sendSensor("stringTest", f.str_msg);
    msg_vector = f.provider.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 2,
        "size before connect: " << msg_vector.size()
    );

    data = msg_vector[0].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.obj_msg->get_flag() == data->get_flag(),
        "msg_vector[0] flag was: " << data->get_flag()
    );

    data = msg_vector[1].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.str_msg->get_flag() == data->get_flag(),
        "msg_vector[1] flag was: " << data->get_flag()
    );

    f.provider.connect();
    sleepMS(WAIT_TIME);
    msg_vector = f.provider.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 0,
        "size after connect: " << msg_vector.size()
    );
}

BOOST_FIXTURE_TEST_CASE( completes_persistent, ClientPairFixture ) {
    provider.completed("test");
}

BOOST_FIXTURE_TEST_CASE( sends_packets, ClientPairFixture ) {
    provider.sendEvent("objectTest", obj_msg);
    provider.sendSensor("objectTest", obj_msg);
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( consumer )
BOOST_AUTO_TEST_CASE( receives_hmdlr_error ) {
    ClientPairFixture f("N/A", "invalid-uuid", false);

    f.consumer.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(f.consumer_error);

    f.consumer_error = false;
}

BOOST_AUTO_TEST_CASE( removes_listener ) {
    ClientPairFixture f("N/A", "invalid-uuid", false);

    f.consumer.removeListener("hmdlr-error");
    f.consumer.connect();
}

BOOST_AUTO_TEST_CASE( authorizes ) {
    ClientPairFixture f("N/A", "valid-uuid", false);
    bool authorized = false;

    f.consumer.on("auth-success", [&](sio::event& ev) {
        authorized = true;
    });
    f.consumer.connect();

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE(authorized);
}

BOOST_AUTO_TEST_CASE( waits_until_ready ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", false);
    vector<hmdlr::delayed_message> msg_vector;
    sio::message::ptr data;

    f.consumer.sendControl(PROVIDER_ONE_UUID, "objectTest", f.obj_msg);
    f.consumer.sendControl(PROVIDER_ONE_UUID, "stringTest", f.str_msg);
    msg_vector = f.consumer.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 2,
        "size before connect: " << msg_vector.size()
    );

    data = msg_vector[0].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.obj_msg->get_flag() == data->get_flag(),
        "msg_vector[0] flag was: " << data->get_flag()
    );

    data = msg_vector[1].packet->get_map()["data"];
    BOOST_REQUIRE_MESSAGE(
        f.str_msg->get_flag() == data->get_flag(),
        "msg_vector[1] flag was: " << data->get_flag()
    );

    f.consumer.connect();
    f.provider.connect();
    sleepMS(WAIT_TIME);
    msg_vector = f.consumer.getDelayedMessages();

    BOOST_REQUIRE_MESSAGE(
        msg_vector.size() == 0,
        "size after connect: " << msg_vector.size()
    );
}

BOOST_AUTO_TEST_CASE( sends_control ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", true);

    f.consumer.sendControl(PROVIDER_ONE_UUID, "objectTest", f.obj_msg);
}

BOOST_FIXTURE_TEST_CASE( sets_filter, ClientPairFixture ) {
    sio::message::ptr filter = sio::object_message::create();

    filter->get_map()["event"] = sio::array_message::create();
    filter->get_map()["sensor"] = sio::array_message::create();

    consumer.setFilter(PROVIDER_ONE_UUID, filter);
}

BOOST_AUTO_TEST_CASE( gets_state ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", true);

    f.provider.sendEvent("objectTest", f.obj_msg);
    f.provider.sendEvent("stringTest", f.str_msg);
    sleepMS(WAIT_TIME);

    sio::message::ptr subtypes = sio::array_message::create();
    subtypes->get_vector().push_back(sio::string_message::create("objectTest"));
    subtypes->get_vector().push_back(sio::string_message::create("stringTest"));

    // schema is the UUID
    f.consumer.getState(PROVIDER_ONE_UUID, subtypes);

    sleepMS(WAIT_TIME);

    BOOST_REQUIRE_MESSAGE(f.event_count == 2, "event_count was: " << f.event_count);
}
BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE( client_pair )
BOOST_AUTO_TEST_CASE ( interaction ) {
    ClientPairFixture f(PROVIDER_ONE_UUID, "schema-uuid", true);

    f.consumer.subscribe(PROVIDER_ONE_UUID);
    sleepMS(WAIT_TIME);
    f.provider.sendEvent("stringTest", f.str_msg);
    f.provider.sendSensor("objectTest", f.obj_msg);
    f.consumer.sendControl(PROVIDER_ONE_UUID, "objectTest", f.obj_msg);

    sleepMS(WAIT_TIME );
    BOOST_REQUIRE_MESSAGE(
        f.event_count == 1,
        "event_count was: " << f.event_count
    );
    BOOST_REQUIRE_MESSAGE(
        f.sensor_count == 1,
        "sensor_count was: " << f.sensor_count
    );
    BOOST_REQUIRE_MESSAGE(
        f.control_count == 1,
        "control_count was: " << f.control_count
    );
}
BOOST_AUTO_TEST_SUITE_END()<|endoftext|>


<commit_before>#include <MainApplication/MainApplication.hpp>

#include <Core/CoreMacros.hpp>

#include <QTimer>
#include <QDir>
#include <QPluginLoader>
#include <QCommandLineParser>

#include <Core/Log/Log.hpp>
#include <Core/String/StringUtils.hpp>
#include <Core/Mesh/MeshUtils.hpp>
#include <Core/Math/LinearAlgebra.hpp>
#include <Core/Math/ColorPresets.hpp>
#include <Core/Tasks/Task.hpp>
#include <Core/Tasks/TaskQueue.hpp>
#include <Core/String/StringUtils.hpp>

#include <Engine/RadiumEngine.hpp>
#include <Engine/Entity/Entity.hpp>
#include <Engine/Managers/SystemDisplay/SystemDisplay.hpp>

#include <Engine/Renderer/Renderer.hpp>
#include <Engine/Renderer/RenderTechnique/RenderTechnique.hpp>
#include <Engine/Renderer/RenderTechnique/Material.hpp>
#include <Engine/Renderer/RenderTechnique/ShaderProgram.hpp>
#include <Engine/Renderer/RenderObject/RenderObjectManager.hpp>
#include <Engine/Renderer/RenderObject/RenderObject.hpp>
#include <Engine/Renderer/Mesh/Mesh.hpp>
#include <Engine/Renderer/Renderers/DebugRender.hpp>
#include <Engine/Renderer/RenderTechnique/ShaderConfigFactory.hpp>

#include <MainApplication/Gui/MainWindow.hpp>
#include <MainApplication/Version.hpp>

#include <MainApplication/PluginBase/RadiumPluginInterface.hpp>

// Const parameters : TODO : make config / command line options

namespace Ra
{
    MainApplication::MainApplication( int argc, char** argv )
        : QApplication( argc, argv )
        , m_mainWindow( nullptr )
        , m_engine( nullptr )
        , m_taskQueue( nullptr )
        , m_viewer( nullptr )
        , m_frameTimer( new QTimer( this ) )
        , m_frameCounter( 0 )
        , m_numFrames( 0 )
        , m_isAboutToQuit( false )
        //, m_timerData(TIMER_AVERAGE)
    {
        m_targetFPS = 60; // Default
        std::string pluginsPath = "../Plugins/bin";

        QCommandLineParser parser;
        parser.setApplicationDescription("Radium Engine RPZ, TMTC");
        parser.addHelpOption();
        parser.addVersionOption();

        // For any reason, the third parameter must be set if you want to be able to read anything from it (and it cannot be "")
        QCommandLineOption fpsOpt(QStringList{"r", "framerate", "fps"}, "Control the application framerate, 0 to disable it (and run as fast as possible)", "60");
        QCommandLineOption pluginOpt(QStringList{"p", "plugins", "pluginsPath"}, "Set the path to the plugin dlls", "../Plugins/bin");
        QCommandLineOption fileOpt(QStringList{"f", "file", "scene"}, "Open a scene file at startup", "foo.bar");
        QCommandLineOption numFramesOpt(QStringList{"n", "numframes"}, "Run for a fixed number of frames", "0");
        // NOTE(Charly): Add other options here

        parser.addOptions({fpsOpt, pluginOpt, fileOpt, numFramesOpt });
        parser.process(*this);

        if (parser.isSet(fpsOpt))       m_targetFPS = parser.value(fpsOpt).toUInt();
        if (parser.isSet(pluginOpt))    pluginsPath = parser.value(pluginOpt).toStdString();
        if (parser.isSet(numFramesOpt)) m_numFrames = parser.value(numFramesOpt).toUInt();

        // Boilerplate print.
        LOG( logINFO ) << "*** Radium Engine Main App  ***";
        std::stringstream config;
#if defined (CORE_DEBUG)
        config << "(Debug Build) -- ";
#else
        config << "(Release Build) -- ";
#endif

#if defined (ARCH_X86)
        config << " 32 bits x86";
#elif defined (ARCH_X64)
        config << " 64 bits x64";
#endif
        LOG( logINFO ) << config.str();

        config.str( std::string() );
        config << "Floating point format : ";
#if defined(CORE_USE_DOUBLE)
        config << "double precision";
#else
        config << "single precision" ;
#endif

        LOG( logINFO ) << config.str();

        config.str( std::string() );
        config<<"build: "<<Version::compiler<<" - "<<Version::compileDate<<" "<<Version::compileTime;

        LOG( logINFO ) << config.str();

        LOG(logINFO) << "Qt Version: " << qVersion();

        // Create default format for Qt.
        QSurfaceFormat format;
        format.setVersion( 4, 4 );
        format.setProfile( QSurfaceFormat::CoreProfile );
        format.setDepthBufferSize( 24 );
        format.setStencilBufferSize( 8 );
        format.setSamples( 16 );
        format.setSwapBehavior( QSurfaceFormat::DoubleBuffer );
        format.setSwapInterval( 0 );
        QSurfaceFormat::setDefaultFormat( format );

        // Create engine
        m_engine.reset(Engine::RadiumEngine::createInstance());
        m_engine->initialize();

        // Create main window.
        m_mainWindow.reset( new Gui::MainWindow );
        m_mainWindow->show();

        addBasicShaders();

        // Allow all events to be processed (thus the viewer should have
        // initialized the OpenGL context..)
        processEvents();

        // Load plugins
        if ( !loadPlugins( pluginsPath ) )
        {
            LOG( logERROR ) << "An error occurred while trying to load plugins.";
        }

        m_viewer = m_mainWindow->getViewer();
        CORE_ASSERT( m_viewer != nullptr, "GUI was not initialized" );
        CORE_ASSERT( m_viewer->context()->isValid(), "OpenGL was not initialized" );

        // Pass the engine to the renderer to complete the initialization process.
        m_viewer->initRenderer();

        // Create task queue with N-1 threads (we keep one for rendering).
        m_taskQueue.reset( new Core::TaskQueue( std::thread::hardware_concurrency() - 1 ) );

        createConnections();

        setupScene();
        emit starting();

        // A file has been required, load it.
        if (parser.isSet(fileOpt))
        {
            loadFile(parser.value(fileOpt));
        }

        m_lastFrameStart = Core::Timer::Clock::now();
    }

    void MainApplication::createConnections()
    {
        connect( m_mainWindow.get(), &Gui::MainWindow::closed , this, &MainApplication::appNeedsToQuit );
    }

    void MainApplication::setupScene()
    {
        using namespace Engine::DrawPrimitives;

        Engine::SystemEntity::uiCmp()->addRenderObject(
            Primitive(Engine::SystemEntity::uiCmp(), Grid(
                    Core::Vector3::Zero(), Core::Vector3::UnitX(),
                    Core::Vector3::UnitZ(), Core::Colors::Grey(0.6f))));

        Engine::SystemEntity::uiCmp()->addRenderObject(
                    Primitive(Engine::SystemEntity::uiCmp(), Frame(Ra::Core::Transform::Identity(), 0.05f)));

    }

    void MainApplication::loadFile( QString path )
    {
        std::string pathStr = path.toLocal8Bit().data();
        LOG(logINFO) << "Loading file " << pathStr << "...";
        bool res = m_engine->loadFile( pathStr );
        CORE_UNUSED( res );
        m_viewer->handleFileLoading( pathStr );

        // Compute new scene aabb
        Core::Aabb aabb;

        std::vector<std::shared_ptr<Engine::RenderObject>> ros;
        m_engine->getRenderObjectManager()->getRenderObjects( ros );

        for ( auto ro : ros )
        {
            auto mesh = ro->getMesh();
            auto pos = mesh->getGeometry().m_vertices;

            for ( auto& p : pos )
            {
                p = ro->getLocalTransform() * p;
            }

            Ra::Core::Vector3 bmin = pos.getMap().rowwise().minCoeff().head<3>();
            Ra::Core::Vector3 bmax = pos.getMap().rowwise().maxCoeff().head<3>();

            aabb.extend( bmin );
            aabb.extend( bmax );
        }

        m_viewer->fitCameraToScene( aabb );

        emit loadComplete();
    }

    void MainApplication::framesCountForStatsChanged( uint count )
    {
        m_frameCountBeforeUpdate = count;
    }

    void MainApplication::addBasicShaders()
    {
        using namespace Ra::Engine;

        ShaderConfiguration bpConfig("BlinnPhong");
        bpConfig.addShader(ShaderType_VERTEX, "../Shaders/BlinnPhong.vert.glsl");
        bpConfig.addShader(ShaderType_FRAGMENT, "../Shaders/BlinnPhong.frag.glsl");
        ShaderConfigurationFactory::addConfiguration(bpConfig);

        ShaderConfiguration pConfig("Plain");
        pConfig.addShader(ShaderType_VERTEX, "../Shaders/Plain.vert.glsl");
        pConfig.addShader(ShaderType_FRAGMENT, "../Shaders/Plain.frag.glsl");
        ShaderConfigurationFactory::addConfiguration(pConfig);

        ShaderConfiguration lgConfig("LinesGeom");
        lgConfig.addShader(ShaderType_VERTEX, "../Shaders/Lines.vert.glsl");
        lgConfig.addShader(ShaderType_FRAGMENT, "../Shaders/Lines.frag.glsl");
        lgConfig.addShader(ShaderType_GEOMETRY, "../Shaders/Lines.geom.glsl");
        ShaderConfigurationFactory::addConfiguration(lgConfig);

        ShaderConfiguration lConfig("Lines");
        lConfig.addShader(ShaderType_VERTEX, "../Shaders/Lines.vert.glsl");
        lConfig.addShader(ShaderType_FRAGMENT, "../Shaders/Lines.frag.glsl");
        ShaderConfigurationFactory::addConfiguration(lConfig);
    }

    void MainApplication::radiumFrame()
    {
        FrameTimerData timerData;
        timerData.frameStart = Core::Timer::Clock::now();

        // ----------
        // 0. Compute time since last frame.
        const Scalar dt = m_realFrameRate ?
                    Core::Timer::getIntervalSeconds( m_lastFrameStart, timerData.frameStart ) :
                    1.f / Scalar(m_targetFPS);
        m_lastFrameStart = timerData.frameStart;

        timerData.eventsStart = Core::Timer::Clock::now();
        processEvents();
        timerData.eventsEnd = Core::Timer::Clock::now();

        // ----------
        // 1. Gather user input and dispatch it.

        // Get picking results from last frame and forward it to the selection.
        m_viewer->processPicking();

        // ----------
        // 2. Kickoff rendering
        m_viewer->startRendering( dt );

        timerData.tasksStart = Core::Timer::Clock::now();

        // ----------
        // 3. Run the engine task queue.
        m_engine->getTasks( m_taskQueue.get(), dt );

        // Run one frame of tasks
        m_taskQueue->startTasks();
        m_taskQueue->waitForTasks();
        timerData.taskData = m_taskQueue->getTimerData();
        m_taskQueue->flushTaskQueue();

        timerData.tasksEnd = Core::Timer::Clock::now();

        // ----------
        // 4. Wait until frame is fully rendered and display.
        m_viewer->waitForRendering();
        m_viewer->update();

        timerData.renderData = m_viewer->getRenderer()->getTimerData();

        // ----------
        // 5. Synchronize whatever needs synchronisation
        m_engine->endFrameSync();

        // ----------
        // 6. Frame end.
        timerData.frameEnd = Core::Timer::Clock::now();
        timerData.numFrame = m_frameCounter;

        m_timerData.push_back( timerData );
        ++m_frameCounter;

        if (m_numFrames > 0  &&  m_frameCounter > m_numFrames )
        {
            appNeedsToQuit();
        }

        if ( m_frameCounter % m_frameCountBeforeUpdate == 0 )
        {
            emit( updateFrameStats( m_timerData ) );
            m_timerData.clear();
        }

        m_mainWindow->onFrameComplete();
    }

    void MainApplication::appNeedsToQuit()
    {
        LOG( logDEBUG ) << "About to quit.";
        m_isAboutToQuit = true;
    }

    void MainApplication::setRealFrameRate(bool on)
    {
       m_realFrameRate = on;
    }

    MainApplication::~MainApplication()
    {
        LOG( logINFO ) << "About to quit... Cleaning RadiumEngine memory";
        emit stopping();
        m_mainWindow->cleanup();
        m_engine->cleanup();
    }

    bool MainApplication::loadPlugins( const std::string& pluginsPath )
    {
        LOG( logINFO )<<" *** Loading Plugins ***";
        QDir pluginsDir( qApp->applicationDirPath() );
        pluginsDir.cd( pluginsPath.c_str() );

        bool res = true;
        uint pluginCpt = 0;

        for (const auto& filename : pluginsDir.entryList(QDir::Files))
//        foreach (QString filename, pluginsDir.entryList( QDir::Files ) )
        {
            PluginContext context;
            context.m_engine = m_engine.get();
            context.m_selectionManager = m_mainWindow->getSelectionManager();

            std::string ext = Core::StringUtils::getFileExt( filename.toStdString() );
#if defined( OS_WINDOWS )
            std::string sysDllExt = "dll";
#elif defined( OS_LINUX )
            std::string sysDllExt = "so";
#elif defined( OS_MACOS )
            std::string sysDllExt = "dylib";
#else
            static_assert( false, "System configuration not handled" );
#endif
            if ( ext == sysDllExt )
            {
                QPluginLoader pluginLoader( pluginsDir.absoluteFilePath( filename ) );
                // Force symbol resolution at load time.
                pluginLoader.setLoadHints( QLibrary::ResolveAllSymbolsHint );

                LOG( logINFO ) << "Found plugin " << filename.toStdString();

                QObject* plugin = pluginLoader.instance();
                Plugins::RadiumPluginInterface* loadedPlugin;

                if ( plugin )
                {
                    loadedPlugin = qobject_cast<Plugins::RadiumPluginInterface*>( plugin );
                    if ( loadedPlugin )
                    {
                        ++pluginCpt;
                        loadedPlugin->registerPlugin( context );
                        m_mainWindow->updateUi( loadedPlugin );
                    }
                    else
                    {
                        LOG( logERROR ) << "Something went wrong while trying to cast plugin"
                                        << filename.toStdString();
                        res = false;
                    }
                }
                else
                {
                    LOG( logERROR ) << "Something went wrong while trying to load plugin "
                                    << filename.toStdString() << " : "
                                    << pluginLoader.errorString().toStdString();
                    res = false;
                }
            }
        }

        if (pluginCpt == 0)
        {
            LOG(logINFO) << "No plugin found or loaded.";
        }
        else
        {
            LOG(logINFO) << "Loaded " << pluginCpt << " plugins.";
        }

        return res;
    }
}
<commit_msg>Configure organization and application names to ease QSettings use<commit_after>#include <MainApplication/MainApplication.hpp>

#include <Core/CoreMacros.hpp>

#include <QTimer>
#include <QDir>
#include <QPluginLoader>
#include <QCommandLineParser>

#include <Core/Log/Log.hpp>
#include <Core/String/StringUtils.hpp>
#include <Core/Mesh/MeshUtils.hpp>
#include <Core/Math/LinearAlgebra.hpp>
#include <Core/Math/ColorPresets.hpp>
#include <Core/Tasks/Task.hpp>
#include <Core/Tasks/TaskQueue.hpp>
#include <Core/String/StringUtils.hpp>

#include <Engine/RadiumEngine.hpp>
#include <Engine/Entity/Entity.hpp>
#include <Engine/Managers/SystemDisplay/SystemDisplay.hpp>

#include <Engine/Renderer/Renderer.hpp>
#include <Engine/Renderer/RenderTechnique/RenderTechnique.hpp>
#include <Engine/Renderer/RenderTechnique/Material.hpp>
#include <Engine/Renderer/RenderTechnique/ShaderProgram.hpp>
#include <Engine/Renderer/RenderObject/RenderObjectManager.hpp>
#include <Engine/Renderer/RenderObject/RenderObject.hpp>
#include <Engine/Renderer/Mesh/Mesh.hpp>
#include <Engine/Renderer/Renderers/DebugRender.hpp>
#include <Engine/Renderer/RenderTechnique/ShaderConfigFactory.hpp>

#include <MainApplication/Gui/MainWindow.hpp>
#include <MainApplication/Version.hpp>

#include <MainApplication/PluginBase/RadiumPluginInterface.hpp>

// Const parameters : TODO : make config / command line options

namespace Ra
{
    MainApplication::MainApplication( int argc, char** argv )
        : QApplication( argc, argv )
        , m_mainWindow( nullptr )
        , m_engine( nullptr )
        , m_taskQueue( nullptr )
        , m_viewer( nullptr )
        , m_frameTimer( new QTimer( this ) )
        , m_frameCounter( 0 )
        , m_numFrames( 0 )
        , m_isAboutToQuit( false )
        //, m_timerData(TIMER_AVERAGE)
    {
        // Set application and organization names in order to ensure uniform
        // QSettings configurations.
        // \see http://doc.qt.io/qt-5/qsettings.html#QSettings-4
        QCoreApplication::setOrganizationName("AGGA-IRIT");
        QCoreApplication::setApplicationName("Radium-Engine");

        m_targetFPS = 60; // Default
        std::string pluginsPath = "../Plugins/bin";

        QCommandLineParser parser;
        parser.setApplicationDescription("Radium Engine RPZ, TMTC");
        parser.addHelpOption();
        parser.addVersionOption();

        // For any reason, the third parameter must be set if you want to be able to read anything from it (and it cannot be "")
        QCommandLineOption fpsOpt(QStringList{"r", "framerate", "fps"}, "Control the application framerate, 0 to disable it (and run as fast as possible)", "60");
        QCommandLineOption pluginOpt(QStringList{"p", "plugins", "pluginsPath"}, "Set the path to the plugin dlls", "../Plugins/bin");
        QCommandLineOption fileOpt(QStringList{"f", "file", "scene"}, "Open a scene file at startup", "foo.bar");
        QCommandLineOption numFramesOpt(QStringList{"n", "numframes"}, "Run for a fixed number of frames", "0");
        // NOTE(Charly): Add other options here

        parser.addOptions({fpsOpt, pluginOpt, fileOpt, numFramesOpt });
        parser.process(*this);

        if (parser.isSet(fpsOpt))       m_targetFPS = parser.value(fpsOpt).toUInt();
        if (parser.isSet(pluginOpt))    pluginsPath = parser.value(pluginOpt).toStdString();
        if (parser.isSet(numFramesOpt)) m_numFrames = parser.value(numFramesOpt).toUInt();

        // Boilerplate print.
        LOG( logINFO ) << "*** Radium Engine Main App  ***";
        std::stringstream config;
#if defined (CORE_DEBUG)
        config << "(Debug Build) -- ";
#else
        config << "(Release Build) -- ";
#endif

#if defined (ARCH_X86)
        config << " 32 bits x86";
#elif defined (ARCH_X64)
        config << " 64 bits x64";
#endif
        LOG( logINFO ) << config.str();

        config.str( std::string() );
        config << "Floating point format : ";
#if defined(CORE_USE_DOUBLE)
        config << "double precision";
#else
        config << "single precision" ;
#endif

        LOG( logINFO ) << config.str();

        config.str( std::string() );
        config<<"build: "<<Version::compiler<<" - "<<Version::compileDate<<" "<<Version::compileTime;

        LOG( logINFO ) << config.str();

        LOG(logINFO) << "Qt Version: " << qVersion();

        // Create default format for Qt.
        QSurfaceFormat format;
        format.setVersion( 4, 4 );
        format.setProfile( QSurfaceFormat::CoreProfile );
        format.setDepthBufferSize( 24 );
        format.setStencilBufferSize( 8 );
        format.setSamples( 16 );
        format.setSwapBehavior( QSurfaceFormat::DoubleBuffer );
        format.setSwapInterval( 0 );
        QSurfaceFormat::setDefaultFormat( format );

        // Create engine
        m_engine.reset(Engine::RadiumEngine::createInstance());
        m_engine->initialize();

        // Create main window.
        m_mainWindow.reset( new Gui::MainWindow );
        m_mainWindow->show();

        addBasicShaders();

        // Allow all events to be processed (thus the viewer should have
        // initialized the OpenGL context..)
        processEvents();

        // Load plugins
        if ( !loadPlugins( pluginsPath ) )
        {
            LOG( logERROR ) << "An error occurred while trying to load plugins.";
        }

        m_viewer = m_mainWindow->getViewer();
        CORE_ASSERT( m_viewer != nullptr, "GUI was not initialized" );
        CORE_ASSERT( m_viewer->context()->isValid(), "OpenGL was not initialized" );

        // Pass the engine to the renderer to complete the initialization process.
        m_viewer->initRenderer();

        // Create task queue with N-1 threads (we keep one for rendering).
        m_taskQueue.reset( new Core::TaskQueue( std::thread::hardware_concurrency() - 1 ) );

        createConnections();

        setupScene();
        emit starting();

        // A file has been required, load it.
        if (parser.isSet(fileOpt))
        {
            loadFile(parser.value(fileOpt));
        }

        m_lastFrameStart = Core::Timer::Clock::now();
    }

    void MainApplication::createConnections()
    {
        connect( m_mainWindow.get(), &Gui::MainWindow::closed , this, &MainApplication::appNeedsToQuit );
    }

    void MainApplication::setupScene()
    {
        using namespace Engine::DrawPrimitives;

        Engine::SystemEntity::uiCmp()->addRenderObject(
            Primitive(Engine::SystemEntity::uiCmp(), Grid(
                    Core::Vector3::Zero(), Core::Vector3::UnitX(),
                    Core::Vector3::UnitZ(), Core::Colors::Grey(0.6f))));

        Engine::SystemEntity::uiCmp()->addRenderObject(
                    Primitive(Engine::SystemEntity::uiCmp(), Frame(Ra::Core::Transform::Identity(), 0.05f)));

    }

    void MainApplication::loadFile( QString path )
    {
        std::string pathStr = path.toLocal8Bit().data();
        LOG(logINFO) << "Loading file " << pathStr << "...";
        bool res = m_engine->loadFile( pathStr );
        CORE_UNUSED( res );
        m_viewer->handleFileLoading( pathStr );

        // Compute new scene aabb
        Core::Aabb aabb;

        std::vector<std::shared_ptr<Engine::RenderObject>> ros;
        m_engine->getRenderObjectManager()->getRenderObjects( ros );

        for ( auto ro : ros )
        {
            auto mesh = ro->getMesh();
            auto pos = mesh->getGeometry().m_vertices;

            for ( auto& p : pos )
            {
                p = ro->getLocalTransform() * p;
            }

            Ra::Core::Vector3 bmin = pos.getMap().rowwise().minCoeff().head<3>();
            Ra::Core::Vector3 bmax = pos.getMap().rowwise().maxCoeff().head<3>();

            aabb.extend( bmin );
            aabb.extend( bmax );
        }

        m_viewer->fitCameraToScene( aabb );

        emit loadComplete();
    }

    void MainApplication::framesCountForStatsChanged( uint count )
    {
        m_frameCountBeforeUpdate = count;
    }

    void MainApplication::addBasicShaders()
    {
        using namespace Ra::Engine;

        ShaderConfiguration bpConfig("BlinnPhong");
        bpConfig.addShader(ShaderType_VERTEX, "../Shaders/BlinnPhong.vert.glsl");
        bpConfig.addShader(ShaderType_FRAGMENT, "../Shaders/BlinnPhong.frag.glsl");
        ShaderConfigurationFactory::addConfiguration(bpConfig);

        ShaderConfiguration pConfig("Plain");
        pConfig.addShader(ShaderType_VERTEX, "../Shaders/Plain.vert.glsl");
        pConfig.addShader(ShaderType_FRAGMENT, "../Shaders/Plain.frag.glsl");
        ShaderConfigurationFactory::addConfiguration(pConfig);

        ShaderConfiguration lgConfig("LinesGeom");
        lgConfig.addShader(ShaderType_VERTEX, "../Shaders/Lines.vert.glsl");
        lgConfig.addShader(ShaderType_FRAGMENT, "../Shaders/Lines.frag.glsl");
        lgConfig.addShader(ShaderType_GEOMETRY, "../Shaders/Lines.geom.glsl");
        ShaderConfigurationFactory::addConfiguration(lgConfig);

        ShaderConfiguration lConfig("Lines");
        lConfig.addShader(ShaderType_VERTEX, "../Shaders/Lines.vert.glsl");
        lConfig.addShader(ShaderType_FRAGMENT, "../Shaders/Lines.frag.glsl");
        ShaderConfigurationFactory::addConfiguration(lConfig);
    }

    void MainApplication::radiumFrame()
    {
        FrameTimerData timerData;
        timerData.frameStart = Core::Timer::Clock::now();

        // ----------
        // 0. Compute time since last frame.
        const Scalar dt = m_realFrameRate ?
                    Core::Timer::getIntervalSeconds( m_lastFrameStart, timerData.frameStart ) :
                    1.f / Scalar(m_targetFPS);
        m_lastFrameStart = timerData.frameStart;

        timerData.eventsStart = Core::Timer::Clock::now();
        processEvents();
        timerData.eventsEnd = Core::Timer::Clock::now();

        // ----------
        // 1. Gather user input and dispatch it.

        // Get picking results from last frame and forward it to the selection.
        m_viewer->processPicking();

        // ----------
        // 2. Kickoff rendering
        m_viewer->startRendering( dt );

        timerData.tasksStart = Core::Timer::Clock::now();

        // ----------
        // 3. Run the engine task queue.
        m_engine->getTasks( m_taskQueue.get(), dt );

        // Run one frame of tasks
        m_taskQueue->startTasks();
        m_taskQueue->waitForTasks();
        timerData.taskData = m_taskQueue->getTimerData();
        m_taskQueue->flushTaskQueue();

        timerData.tasksEnd = Core::Timer::Clock::now();

        // ----------
        // 4. Wait until frame is fully rendered and display.
        m_viewer->waitForRendering();
        m_viewer->update();

        timerData.renderData = m_viewer->getRenderer()->getTimerData();

        // ----------
        // 5. Synchronize whatever needs synchronisation
        m_engine->endFrameSync();

        // ----------
        // 6. Frame end.
        timerData.frameEnd = Core::Timer::Clock::now();
        timerData.numFrame = m_frameCounter;

        m_timerData.push_back( timerData );
        ++m_frameCounter;

        if (m_numFrames > 0  &&  m_frameCounter > m_numFrames )
        {
            appNeedsToQuit();
        }

        if ( m_frameCounter % m_frameCountBeforeUpdate == 0 )
        {
            emit( updateFrameStats( m_timerData ) );
            m_timerData.clear();
        }

        m_mainWindow->onFrameComplete();
    }

    void MainApplication::appNeedsToQuit()
    {
        LOG( logDEBUG ) << "About to quit.";
        m_isAboutToQuit = true;
    }

    void MainApplication::setRealFrameRate(bool on)
    {
       m_realFrameRate = on;
    }

    MainApplication::~MainApplication()
    {
        LOG( logINFO ) << "About to quit... Cleaning RadiumEngine memory";
        emit stopping();
        m_mainWindow->cleanup();
        m_engine->cleanup();
    }

    bool MainApplication::loadPlugins( const std::string& pluginsPath )
    {
        LOG( logINFO )<<" *** Loading Plugins ***";
        QDir pluginsDir( qApp->applicationDirPath() );
        pluginsDir.cd( pluginsPath.c_str() );

        bool res = true;
        uint pluginCpt = 0;

        for (const auto& filename : pluginsDir.entryList(QDir::Files))
//        foreach (QString filename, pluginsDir.entryList( QDir::Files ) )
        {
            PluginContext context;
            context.m_engine = m_engine.get();
            context.m_selectionManager = m_mainWindow->getSelectionManager();

            std::string ext = Core::StringUtils::getFileExt( filename.toStdString() );
#if defined( OS_WINDOWS )
            std::string sysDllExt = "dll";
#elif defined( OS_LINUX )
            std::string sysDllExt = "so";
#elif defined( OS_MACOS )
            std::string sysDllExt = "dylib";
#else
            static_assert( false, "System configuration not handled" );
#endif
            if ( ext == sysDllExt )
            {
                QPluginLoader pluginLoader( pluginsDir.absoluteFilePath( filename ) );
                // Force symbol resolution at load time.
                pluginLoader.setLoadHints( QLibrary::ResolveAllSymbolsHint );

                LOG( logINFO ) << "Found plugin " << filename.toStdString();

                QObject* plugin = pluginLoader.instance();
                Plugins::RadiumPluginInterface* loadedPlugin;

                if ( plugin )
                {
                    loadedPlugin = qobject_cast<Plugins::RadiumPluginInterface*>( plugin );
                    if ( loadedPlugin )
                    {
                        ++pluginCpt;
                        loadedPlugin->registerPlugin( context );
                        m_mainWindow->updateUi( loadedPlugin );
                    }
                    else
                    {
                        LOG( logERROR ) << "Something went wrong while trying to cast plugin"
                                        << filename.toStdString();
                        res = false;
                    }
                }
                else
                {
                    LOG( logERROR ) << "Something went wrong while trying to load plugin "
                                    << filename.toStdString() << " : "
                                    << pluginLoader.errorString().toStdString();
                    res = false;
                }
            }
        }

        if (pluginCpt == 0)
        {
            LOG(logINFO) << "No plugin found or loaded.";
        }
        else
        {
            LOG(logINFO) << "Loaded " << pluginCpt << " plugins.";
        }

        return res;
    }
}
<|endoftext|>